001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.scm.provider.git.jgit.command.checkin;
020
021import java.io.File;
022import java.io.FileWriter;
023import java.io.IOException;
024import java.io.PrintWriter;
025
026import org.apache.maven.scm.ScmException;
027import org.apache.maven.scm.ScmFileSet;
028import org.apache.maven.scm.command.add.AddScmResult;
029import org.apache.maven.scm.command.checkin.CheckInScmResult;
030import org.apache.maven.scm.provider.git.GitScmTestUtils;
031import org.apache.maven.scm.provider.git.command.checkin.GitCheckInCommandTckTest;
032import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
033import org.apache.maven.scm.repository.ScmRepository;
034import org.codehaus.plexus.util.IOUtil;
035import org.eclipse.jgit.api.Git;
036import org.eclipse.jgit.lib.AnyObjectId;
037import org.eclipse.jgit.lib.Config;
038import org.eclipse.jgit.lib.Constants;
039import org.eclipse.jgit.lib.Repository;
040import org.eclipse.jgit.lib.StoredConfig;
041import org.eclipse.jgit.revwalk.RevCommit;
042import org.eclipse.jgit.revwalk.RevWalk;
043import org.eclipse.jgit.storage.file.FileBasedConfig;
044import org.eclipse.jgit.util.FS;
045import org.eclipse.jgit.util.FileUtils;
046import org.eclipse.jgit.util.SystemReader;
047import org.junit.After;
048import org.junit.Before;
049import org.junit.Test;
050
051import static org.junit.Assert.assertEquals;
052import static org.junit.Assert.assertFalse;
053import static org.junit.Assert.assertNotNull;
054import static org.junit.Assert.assertTrue;
055
056/**
057 * @author Dominik Bartholdi (imod)
058 */
059public class JGitCheckInCommandCommitterAuthorTckTest extends GitCheckInCommandTckTest {
060
061    @Before
062    @Override
063    public void setUp() throws Exception {
064        super.setUp();
065
066        SystemReader.setInstance(new CustomSystemReader());
067    }
068
069    @After
070    @Override
071    public void tearDown() throws Exception {
072        super.tearDown();
073
074        // back to default
075        SystemReader.setInstance(null);
076    }
077
078    /**
079     * {@inheritDoc}
080     */
081    public String getScmUrl() throws Exception {
082        return GitScmTestUtils.getScmUrl(getRepositoryRoot(), "jgit");
083    }
084
085    @Override
086    protected void deleteDirectory(File directory) throws IOException {
087        if (directory.exists()) {
088            FileUtils.delete(directory, FileUtils.RECURSIVE | FileUtils.RETRY);
089        }
090    }
091
092    @Override
093    @Test
094    public void testCheckInCommandTest() throws Exception {
095        File fooJava = new File(getWorkingCopy(), "src/main/java/Foo.java");
096        assertFalse("check Foo.java doesn't yet exist", fooJava.canRead());
097
098        Git git = Git.open(getWorkingCopy());
099
100        RevCommit head = getHeadCommit(git.getRepository());
101        // Mark created the test repo...
102        assertEquals("Mark Struberg", head.getCommitterIdent().getName());
103        JGitUtils.closeRepo(git);
104
105        createAndCommitFile(fooJava, null);
106
107        // change user in config
108        git = Git.open(getWorkingCopy());
109        StoredConfig config = git.getRepository().getConfig();
110        unsetConfig(config);
111        config.setString("user", null, "name", "Dominik");
112        config.setString("user", null, "email", "domi@mycomp.com");
113        config.save();
114
115        // make a commit
116        createAndCommitFile(fooJava, null);
117
118        // check new commit is done with new user in config
119        head = getHeadCommit(git.getRepository());
120        assertEquals("Dominik", head.getCommitterIdent().getName());
121        assertEquals("Dominik", head.getAuthorIdent().getName());
122        assertEquals("domi@mycomp.com", head.getAuthorIdent().getEmailAddress());
123        assertEquals("domi@mycomp.com", head.getCommitterIdent().getEmailAddress());
124        JGitUtils.closeRepo(git);
125
126        // change user in config
127        git = Git.open(getWorkingCopy());
128        config = git.getRepository().getConfig();
129        unsetConfig(config);
130        config.setString("user", null, "name", "dbartholdi");
131        config.save();
132
133        // make a change
134        createAndCommitFile(fooJava, null);
135
136        // check new commit is done with new user in config
137        head = getHeadCommit(git.getRepository());
138        assertEquals("dbartholdi", head.getCommitterIdent().getName());
139        assertFalse(
140                "no mail domain is configured, git system default should be used",
141                head.getCommitterIdent().getEmailAddress().contains("dbartholdi"));
142        JGitUtils.closeRepo(git);
143
144        // unset a user and maven user but set default mail domain
145        git = Git.open(getWorkingCopy());
146        config = git.getRepository().getConfig();
147        unsetConfig(config);
148        config.setString(JGitCheckInCommand.GIT_MAVEN_SECTION, null, JGitCheckInCommand.GIT_MAILDOMAIN, "comp.com");
149        config.save();
150
151        // make a change with an user on the commandline
152        createAndCommitFile(fooJava, "dude");
153
154        // check new commit is done with new maven user in config
155        head = getHeadCommit(git.getRepository());
156        assertEquals("dude", head.getCommitterIdent().getName());
157        assertEquals("dude@comp.com", head.getCommitterIdent().getEmailAddress());
158        assertEquals("dude", head.getAuthorIdent().getName());
159        assertEquals("dude@comp.com", head.getAuthorIdent().getEmailAddress());
160        JGitUtils.closeRepo(git);
161
162        // unset a user and maven user but set default mail domain
163        git = Git.open(getWorkingCopy());
164        config = git.getRepository().getConfig();
165        unsetConfig(config);
166        config.setString("user", null, "name", "dbartholdi");
167        config.setBoolean(JGitCheckInCommand.GIT_MAVEN_SECTION, null, JGitCheckInCommand.GIT_FORCE, true);
168        config.setString(JGitCheckInCommand.GIT_MAVEN_SECTION, null, JGitCheckInCommand.GIT_MAILDOMAIN, "anycomp.com");
169        config.save();
170
171        // make a change with an user on the commandline
172        createAndCommitFile(fooJava, "dude");
173
174        // check new commit is done with new maven user in config
175        head = getHeadCommit(git.getRepository());
176        assertEquals("dude", head.getCommitterIdent().getName());
177        assertEquals("dude@anycomp.com", head.getCommitterIdent().getEmailAddress());
178        assertEquals("dude", head.getAuthorIdent().getName());
179        assertEquals("dude@anycomp.com", head.getAuthorIdent().getEmailAddress());
180        JGitUtils.closeRepo(git);
181
182        // unset a user and maven user but set default mail domain
183        git = Git.open(getWorkingCopy());
184        config = git.getRepository().getConfig();
185        unsetConfig(config);
186        config.setString(JGitCheckInCommand.GIT_MAVEN_SECTION, null, JGitCheckInCommand.GIT_MAILDOMAIN, "anycomp.com");
187        config.save();
188
189        // make a change with no username given
190        createAndCommitFile(fooJava, null);
191
192        // check new commit does not contain the configured email domain
193        head = getHeadCommit(git.getRepository());
194        assertFalse(head.getCommitterIdent().getEmailAddress().contains("anycomp.com"));
195        assertFalse(head.getAuthorIdent().getEmailAddress().contains("anycomp.com"));
196        JGitUtils.closeRepo(git);
197
198        // unset a user and full maven section
199        git = Git.open(getWorkingCopy());
200        config = git.getRepository().getConfig();
201        unsetConfig(config);
202        config.save();
203
204        // make a change with an user on the commandline
205        createAndCommitFile(fooJava, "dundy");
206
207        // check new commit is done with new maven user in config
208        head = getHeadCommit(git.getRepository());
209        assertEquals("dundy", head.getCommitterIdent().getName());
210        assertEquals("dundy", head.getAuthorIdent().getName());
211        assertTrue(
212                "the maven user (from parameter) name must be in the committer mail when nothing else is configured",
213                head.getCommitterIdent().getEmailAddress().contains("dundy"));
214        assertTrue(
215                "the user name (from parameter) must be in the author mail when nothing else is configured",
216                head.getAuthorIdent().getEmailAddress().contains("dundy"));
217        JGitUtils.closeRepo(git);
218
219        // unset all configs
220        git = Git.open(getWorkingCopy());
221        config = git.getRepository().getConfig();
222        unsetConfig(config);
223        config.save();
224
225        // make a change with no user on the commandline
226        createAndCommitFile(fooJava, null);
227
228        // check new commit is has a committer/author with email set
229        head = getHeadCommit(git.getRepository());
230        assertNotNull(head.getCommitterIdent().getName());
231        assertNotNull(head.getAuthorIdent().getName());
232        assertNotNull(head.getCommitterIdent().getEmailAddress());
233        assertNotNull(head.getAuthorIdent().getEmailAddress());
234        JGitUtils.closeRepo(git);
235    }
236
237    /**
238     * make sure the local .gitconfig is in a clean state
239     */
240    private void unsetConfig(StoredConfig config) {
241        config.unsetSection("user", null);
242        config.unset("user", null, "name");
243        // somehow unset does not always work on "user"
244        config.setString("user", null, "name", null);
245        config.setString("user", null, "email", null);
246        config.unsetSection(JGitCheckInCommand.GIT_MAVEN_SECTION, null);
247    }
248
249    private void createAndCommitFile(File file, String username) throws Exception, ScmException, IOException {
250        createFooJava(file);
251
252        ScmRepository scmRepository = getScmRepository();
253        scmRepository.getProviderRepository().setUser(username);
254        AddScmResult addResult = getScmManager().add(scmRepository, new ScmFileSet(getWorkingCopy(), "**/*.java"));
255
256        assertResultIsSuccess(addResult);
257
258        CheckInScmResult result = getScmManager()
259                .checkIn(scmRepository, new ScmFileSet(getWorkingCopy(), "**/Foo.java"), "Commit message");
260
261        assertResultIsSuccess(result);
262    }
263
264    private RevCommit getHeadCommit(Repository repository) throws Exception {
265        RevWalk rw = new RevWalk(repository);
266        AnyObjectId headId = repository.resolve(Constants.HEAD);
267        RevCommit head = rw.parseCommit(headId);
268        rw.close();
269        return head;
270    }
271
272    private void createFooJava(File fooJava) throws Exception {
273        FileWriter output = new FileWriter(fooJava);
274
275        PrintWriter printer = new PrintWriter(output);
276        try {
277            printer.println("public class Foo");
278            printer.println("{");
279
280            printer.println("    public void foo()");
281            printer.println("    {");
282            printer.println("        //" + System.currentTimeMillis());
283            printer.println("        int i = 10;");
284            printer.println("    }");
285
286            printer.println("}");
287        } finally {
288            IOUtil.close(output);
289            IOUtil.close(printer);
290        }
291    }
292
293    /**
294     * SystemReader for testing to have full control some imported getters
295     *
296     * @author Robert Scholte
297     */
298    class CustomSystemReader extends SystemReader {
299
300        private final SystemReader reader = SystemReader.getInstance();
301
302        // Ensure environment properties from CI server don't get pulled in
303        public String getenv(String variable) {
304            return null;
305        }
306
307        @Override
308        public String getHostname() {
309            return reader.getHostname();
310        }
311
312        @Override
313        public String getProperty(String key) {
314            return reader.getProperty(key);
315        }
316
317        @Override
318        public FileBasedConfig openSystemConfig(Config parent, FS fs) {
319            return reader.openSystemConfig(parent, fs);
320        }
321
322        @Override
323        public FileBasedConfig openUserConfig(Config parent, FS fs) {
324            return reader.openUserConfig(parent, fs);
325        }
326
327        @Override
328        public long getCurrentTime() {
329            return reader.getCurrentTime();
330        }
331
332        @Override
333        public int getTimezone(long when) {
334            return reader.getTimezone(when);
335        }
336
337        @Override
338        public FileBasedConfig openJGitConfig(Config config, FS fs) {
339            return reader.openJGitConfig(config, fs);
340        }
341    }
342}