From 0047fbba99b804d268a66ed7504a568596de6168 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 27 May 2014 18:13:30 -0400 Subject: [PATCH] Simplified repository creation with a NewRepositoryPage --- .gitmodules | 3 + build.xml | 6 + releases.moxie | 2 + src/main/distrib/data/gitblit.properties | 5 + src/main/distrib/data/gitignore | 1 + src/main/java/com/gitblit/Constants.java | 8 + .../com/gitblit/servlet/GitblitContext.java | 16 + .../com/gitblit/wicket/GitBlitWebApp.java | 10 + .../gitblit/wicket/GitBlitWebApp.properties | 17 +- .../wicket/pages/EditRepositoryPage.java | 16 +- .../wicket/pages/NewRepositoryPage.html | 98 ++++ .../wicket/pages/NewRepositoryPage.java | 493 ++++++++++++++++++ .../com/gitblit/wicket/pages/RootPage.java | 2 +- .../com/gitblit/wicket/pages/UserPage.java | 4 +- .../panels/FilterableRepositoryList.java | 3 +- .../wicket/panels/RepositoriesPanel.java | 5 +- 16 files changed, 674 insertions(+), 15 deletions(-) create mode 100644 .gitmodules create mode 160000 src/main/distrib/data/gitignore create mode 100644 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..01eaa2c8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/main/distrib/data/gitignore"] + path = src/main/distrib/data/gitignore + url = https://github.com/github/gitignore.git diff --git a/build.xml b/build.xml index f45c4ca9..be6f1dd2 100644 --- a/build.xml +++ b/build.xml @@ -919,6 +919,12 @@ + + + + + + diff --git a/releases.moxie b/releases.moxie index 4332238d..5aa207fa 100644 --- a/releases.moxie +++ b/releases.moxie @@ -36,6 +36,7 @@ r24: { - Add FORK_REPOSITORY RPC request type (issue-371, pr-161, ticket-65) - Add object type (ot) parameter for RSS queries to retrieve tag details (pr-165, ticket-66) - Add setting to allow STARTTLS without requiring SMTPS (pr-183) + - Simplified repository creation, offer simple README generation, and insertion of a pre-defined .gitignore file (ticket-76) - Added an extension point for monitoring onStartup and onShutdown (ticket-79) - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85) - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) @@ -55,6 +56,7 @@ r24: { - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } - { name: 'mail.starttls', defaultValue: 'false' } - { name: 'execution.defaultThreadPoolSize', defaultValue: '1' } + - { name: 'git.gitignoreFolder', defaultValue: '${baseFolder}/gitignore' } } # diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 6f55a3eb..d5623cd5 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -271,6 +271,11 @@ git.defaultIncrementalPushTagPrefix = r # SINCE 1.4.0 git.createRepositoriesShared = false +# Directory for gitignore templates used during repository creation. +# +# SINCE 1.6.0 +git.gitignoreFolder = ${baseFolder}/gitignore + # Enable JGit-based garbage collection. (!!EXPERIMENTAL!!) # # USE AT YOUR OWN RISK! diff --git a/src/main/distrib/data/gitignore b/src/main/distrib/data/gitignore new file mode 160000 index 00000000..097db81c --- /dev/null +++ b/src/main/distrib/data/gitignore @@ -0,0 +1 @@ +Subproject commit 097db81c08b138dea7cb031eb18eeb16afe44bdf diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 95eb944a..3e307537 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -122,6 +122,14 @@ public class Constants { public static final String R_TICKETS_PATCHSETS = "refs/tickets/"; + public static final String R_MASTER = "refs/heads/master"; + + public static final String MASTER = "master"; + + public static final String R_DEVELOP = "refs/heads/develop"; + + public static final String DEVELOP = "develop"; + public static String getVersion() { String v = Constants.class.getPackage().getImplementationVersion(); if (v == null) { diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java index 110e553c..50f22d5a 100644 --- a/src/main/java/com/gitblit/servlet/GitblitContext.java +++ b/src/main/java/com/gitblit/servlet/GitblitContext.java @@ -372,6 +372,22 @@ public class GitblitContext extends DaggerContext { } } + // Copy the included gitignore files to the configured gitignore folder + String gitignorePath = webxmlSettings.getString(Keys.git.gitignoreFolder, "gitignore"); + File localGitignores = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, gitignorePath); + if (!localGitignores.exists()) { + File warGitignores = new File(contextFolder, "/WEB-INF/data/gitignore"); + if (!warGitignores.equals(localGitignores)) { + try { + com.gitblit.utils.FileUtils.copy(localGitignores, warGitignores.listFiles()); + } catch (IOException e) { + logger.error(MessageFormat.format( + "Failed to copy included .gitignore files from {0} to {1}", + warGitignores, localGitignores)); + } + } + } + // merge the WebXmlSettings into the runtime settings (for backwards-compatibilty) runtimeSettings.merge(webxmlSettings); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index 7291d039..f63ff3d9 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -57,6 +57,7 @@ import com.gitblit.wicket.pages.ComparePage; import com.gitblit.wicket.pages.DocPage; import com.gitblit.wicket.pages.DocsPage; import com.gitblit.wicket.pages.EditMilestonePage; +import com.gitblit.wicket.pages.EditRepositoryPage; import com.gitblit.wicket.pages.EditTicketPage; import com.gitblit.wicket.pages.ExportTicketPage; import com.gitblit.wicket.pages.FederationRegistrationPage; @@ -71,6 +72,7 @@ import com.gitblit.wicket.pages.MetricsPage; import com.gitblit.wicket.pages.MyDashboardPage; import com.gitblit.wicket.pages.MyTicketsPage; import com.gitblit.wicket.pages.NewMilestonePage; +import com.gitblit.wicket.pages.NewRepositoryPage; import com.gitblit.wicket.pages.NewTicketPage; import com.gitblit.wicket.pages.OverviewPage; import com.gitblit.wicket.pages.PatchPage; @@ -92,6 +94,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { private final Class homePageClass = MyDashboardPage.class; + private final Class newRepositoryPageClass = NewRepositoryPage.class; + private final Map cacheablePages = new HashMap(); private final IStoredSettings settings; @@ -207,6 +211,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { mount("/proposal", ReviewProposalPage.class, "t"); mount("/registration", FederationRegistrationPage.class, "u", "n"); + mount("/new", NewRepositoryPage.class); + mount("/edit", EditRepositoryPage.class, "r"); mount("/activity", ActivityPage.class, "r", "h"); mount("/lucene", LuceneSearchPage.class); mount("/project", ProjectPage.class, "p"); @@ -262,6 +268,10 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { return homePageClass; } + public Class getNewRepositoryPage() { + return newRepositoryPageClass; + } + /* (non-Javadoc) * @see com.gitblit.wicket.Webapp#isCacheablePage(java.lang.String) */ diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 12430ade..ac589558 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -685,4 +685,19 @@ gb.closedMilestones = closed milestones gb.administration = administration gb.plugins = plugins gb.extensions = extensions - +gb.anonymous = Anonymous +gb.anonymousRepoDescription = Anyone can see, clone, and push to this repository. +gb.public = Public +gb.publicRepoDescription = Anyone can see and clone this repository. You choose who can push. +gb.protected = Protected +gb.protectedRepoDescription = Anyone can see this repository. You choose who can clone and push. +gb.private = Private +gb.privateRepoDescription = You choose who can see, clone, and push to this repository. +gb.initialCommit = Initial Commit +gb.initialCommitDescription = This will allow you to git clone this repository immediately. Skip this step if you have already run git init locally. +gb.initWithReadme = Include a README +gb.initWithReadmeDescription = This will generate a simple README document for your repository. +gb.initWithGitignore = Include a .gitignore file +gb.initWithGitignoreDescription = This will insert a config file that instructs your Git clients to ignore files or directories that match defined patterns. +gb.initWithGitflow = Include a .gitflow file +gb.initWithGitflowDescription = This will generate a config file which guides Git clients in setting up Gitflow branches. \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 412c0ecc..c18cd514 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -429,11 +429,7 @@ public class EditRepositoryPage extends RootSubPage { return; } setRedirect(false); - if (isCreate) { - setResponsePage(RepositoriesPage.class); - } else { - setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); - } + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); } }; @@ -632,7 +628,15 @@ public class EditRepositoryPage extends RootSubPage { if (canDelete) { if (app().repositories().deleteRepositoryModel(latestModel)) { info(MessageFormat.format(getString("gb.repositoryDeleted"), latestModel)); - setResponsePage(RepositoriesPage.class); + if (latestModel.isPersonalRepository()) { + // redirect to user's profile page + String prefix = app().settings().getString(Keys.git.userRepositoryPrefix, "~"); + String username = latestModel.projectPath.substring(prefix.length()); + setResponsePage(UserPage.class, WicketUtils.newUsernameParameter(username)); + } else { + // redirect to server repositories page + setResponsePage(RepositoriesPage.class); + } } else { error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), latestModel)); } diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html new file mode 100644 index 00000000..e9f12027 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -0,0 +1,98 @@ + + + + + +
+
+
+ + + + + + + + + + + + + + +
/  
+ +
+
+ +
+ +
+ + +
+
+ + +
+
+
+ +
+
+
+ +
+ +

+
+

+
+ +
+
+ +
+
+
+

+
+
+ +
+ +
+ +
+
+ +

+
+
+ +
+
+ +
+
+
+

+

+
+
+ + + + + \ No newline at end of file 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 00000000..b0cc3e95 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -0,0 +1,493 @@ +/* + * 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.Serializable; +import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.behavior.SimpleAttributeModifier; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.Radio; +import org.apache.wicket.markup.html.form.RadioGroup; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +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; + +public class NewRepositoryPage extends RootSubPage { + + private final RepositoryModel repositoryModel; + private RadioGroup permissionGroup; + private IModel addReadmeModel; + private Model gitignoreModel; + private IModel addGitflowModel; + private IModel addGitignoreModel; + + 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 getRootNavPageClass() { + return RepositoriesPage.class; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + CompoundPropertyModel rModel = new CompoundPropertyModel<>(repositoryModel); + Form form = new Form("editForm", rModel) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + // confirm a repository name was entered + if (StringUtils.isEmpty(repositoryModel.name)) { + error(getString("gb.pleaseSetRepositoryName")); + return; + } + + String project = repositoryModel.projectPath; + String fullName = (project + "/" + repositoryModel.name).trim(); + fullName = fullName.replace('\\', '/'); + fullName = fullName.replace("//", "/"); + if (fullName.charAt(0) == '/') { + fullName = fullName.substring(1); + } + if (fullName.endsWith("/")) { + fullName = fullName.substring(0, fullName.length() - 1); + } + + try { + if (fullName.contains("../")) { + error(getString("gb.illegalRelativeSlash")); + return; + } + if (fullName.contains("/../")) { + error(getString("gb.illegalRelativeSlash")); + return; + } + + // confirm valid characters in repository name + Character c = StringUtils.findInvalidCharacter(fullName); + if (c != null) { + error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), + c)); + return; + } + + repositoryModel.name = fullName; + repositoryModel.projectPath = null; + + Permission permisison = permissionGroup.getModelObject(); + repositoryModel.accessRestriction = permisison.type; + repositoryModel.authorizationControl = AuthorizationControl.NAMED; + + repositoryModel.owners = new ArrayList(); + 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("Please select a .gitignore file"); + } + } + + // 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()); + + // restore project and name fields on error condition + repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName); + if (!StringUtils.isEmpty(repositoryModel.projectPath)) { + repositoryModel.name = fullName.substring(repositoryModel.projectPath.length() + 1); + } + return; + } + setRedirect(true); + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(fullName)); + } + }; + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + + // build project list for repository destination + String defaultProject = null; + List projects = new ArrayList(); + + if (user.canAdmin()) { + String main = app().settings().getString(Keys.web.repositoryRootGroupName, "main"); + projects.add(main); + defaultProject = main; + } + + if (user.canCreate()) { + projects.add(user.getPersonalPath()); + if (defaultProject == null) { + // only prefer personal namespace if default is not already set + defaultProject = user.getPersonalPath(); + } + } + + repositoryModel.projectPath = defaultProject; + + // do not let the browser pre-populate these fields + form.add(new SimpleAttributeModifier("autocomplete", "off")); + + form.add(new DropDownChoice("projectPath", projects)); + form.add(new TextField("name")); + form.add(new TextField("description")); + + Permission anonymousPermission = new Permission(getString("gb.anonymous"), getString("gb.anonymousRepoDescription"), "blank.png", AccessRestrictionType.NONE); + Permission publicPermission = new Permission(getString("gb.public"), getString("gb.publicRepoDescription"), "lock_go_16x16.png", AccessRestrictionType.PUSH); + Permission protectedPermission = new Permission(getString("gb.protected"), getString("gb.protectedRepoDescription"), "lock_pull_16x16.png", AccessRestrictionType.CLONE); + Permission privatePermission = new Permission(getString("gb.private"), getString("gb.privateRepoDescription"), "shield_16x16.png", AccessRestrictionType.VIEW); + + List permissions = new ArrayList(); + if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { + permissions.add(anonymousPermission); + } + permissions.add(publicPermission); + permissions.add(protectedPermission); + permissions.add(privatePermission); + + // determine default permission selection + AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName( + app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name())); + if (AccessRestrictionType.NONE == defaultRestriction) { + defaultRestriction = AccessRestrictionType.PUSH; + } + + Permission defaultPermission = publicPermission; + for (Permission permission : permissions) { + if (permission.type == defaultRestriction) { + defaultPermission = permission; + } + } + + permissionGroup = new RadioGroup<>("permissionsGroup", new Model(defaultPermission)); + form.add(permissionGroup); + + ListView permissionsList = new ListView("permissions", permissions) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem item) { + Permission p = item.getModelObject(); + item.add(new Radio("radio", item.getModel())); + item.add(WicketUtils.newImage("image", p.image)); + item.add(new Label("name", p.name)); + item.add(new Label("description", p.description)); + } + }; + permissionGroup.add(permissionsList); + + // + // initial commit options + // + + // add README + addReadmeModel = Model.of(false); + form.add(new CheckBox("addReadme", 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 gitignores = new ArrayList(); + for (File file : files) { + if (file.isFile() && file.getName().endsWith(".gitignore")) { + gitignores.add(StringUtils.stripFileExtension(file.getName())); + } + } + Collections.sort(gitignores); + gitignoreModel = Model.of(""); + final DropDownChoice gitignoreChoice = new DropDownChoice("gitignore", gitignoreModel, gitignores); + gitignoreChoice.setOutputMarkupId(true); + form.add(gitignoreChoice.setEnabled(false)); + + addGitignoreModel = Model.of(false); + final CheckBox gitignoreCheckbox = new CheckBox("addGitignore", addGitignoreModel); + form.add(gitignoreCheckbox); + + gitignoreCheckbox.add(new AjaxFormComponentUpdatingBehavior("onchange") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onUpdate(AjaxRequestTarget target) { + gitignoreChoice.setEnabled(addGitignoreModel.getObject()); + target.addComponent(gitignoreChoice); + } + }); + + // TODO add .gitflow + addGitflowModel = Model.of(false); + form.add(new CheckBox("addGitflow", addGitflowModel)); + + 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; + } + + private static class Permission implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String description; + final String image; + final AccessRestrictionType type; + + Permission(String name, String description, String img, AccessRestrictionType type) { + this.name = name; + this.description = description; + this.image = img; + this.type = type; + } + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index a2f3a497..b1c3639d 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -607,7 +607,7 @@ public abstract class RootPage extends BasePage { List standardItems = new ArrayList(); standardItems.add(new MenuDivider()); if (user.canAdmin() || user.canCreate()) { - standardItems.add(new PageLinkMenuItem("gb.newRepository", EditRepositoryPage.class)); + standardItems.add(new PageLinkMenuItem("gb.newRepository", app().getNewRepositoryPage())); } standardItems.add(new PageLinkMenuItem("gb.myProfile", UserPage.class, WicketUtils.newUsernameParameter(user.username))); diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 6cb791eb..29b49b33 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -30,8 +30,8 @@ import org.eclipse.jgit.lib.PersonIdent; import com.gitblit.Keys; import com.gitblit.models.Menu.ParameterMenuItem; -import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.NavLink; +import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; @@ -95,7 +95,7 @@ public class UserPage extends RootPage { UserModel sessionUser = GitBlitWebSession.get().getUser(); if (sessionUser != null && user.canCreate() && sessionUser.equals(user)) { // user can create personal repositories - add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); } else { add(new Label("newRepository").setVisible(false)); } diff --git a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java index 45b0bab1..4433b043 100644 --- a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java +++ b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java @@ -33,7 +33,6 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.freemarker.FreemarkerPanel; import com.gitblit.wicket.ng.NgController; -import com.gitblit.wicket.pages.EditRepositoryPage; /** * A client-side filterable rich repository list which uses Freemarker, Wicket, @@ -98,7 +97,7 @@ public class FilterableRepositoryList extends BasePanel { } if (allowCreate) { - panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class)); + panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), app().getNewRepositoryPage())); } else { panel.add(new Label(ngList + "Button").setVisible(false)); } diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java index dd208e23..8573e1a6 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java @@ -51,7 +51,6 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.pages.BasePage; -import com.gitblit.wicket.pages.EditRepositoryPage; import com.gitblit.wicket.pages.ProjectPage; import com.gitblit.wicket.pages.RepositoriesPage; import com.gitblit.wicket.pages.SummaryPage; @@ -87,12 +86,12 @@ public class RepositoriesPanel extends BasePanel { setResponsePage(RepositoriesPage.class); } }.setVisible(app().settings().getBoolean(Keys.git.cacheRepositoryList, true))); - managementLinks.add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + managementLinks.add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); add(managementLinks); } else if (showManagement && user != null && user.canCreate()) { // user can create personal repositories managementLinks = new Fragment("managementPanel", "personalLinks", this); - managementLinks.add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + managementLinks.add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); add(managementLinks); } else { // user has no management permissions -- 2.39.5