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.command.checkin;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.nio.file.Files;
025import java.nio.file.Path;
026import java.nio.file.StandardCopyOption;
027
028import org.apache.maven.scm.CommandParameter;
029import org.apache.maven.scm.CommandParameters;
030import org.apache.maven.scm.PlexusJUnit4TestCase;
031import org.apache.maven.scm.ScmException;
032import org.apache.maven.scm.ScmFileSet;
033import org.apache.maven.scm.command.checkin.CheckInScmResult;
034import org.apache.maven.scm.command.checkout.CheckOutScmResult;
035import org.apache.maven.scm.provider.git.GitScmTestUtils;
036import org.apache.maven.scm.provider.git.util.GitUtil;
037import org.apache.maven.scm.repository.ScmRepository;
038import org.apache.maven.scm.tck.command.checkin.CheckInCommandTckTest;
039import org.codehaus.plexus.util.FileUtils;
040import org.junit.Test;
041
042import static org.junit.Assert.assertFalse;
043
044/**
045 * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
046 */
047public abstract class GitCheckInCommandTckTest extends CheckInCommandTckTest {
048
049    /**
050     * {@inheritDoc}
051     */
052    public void initRepo() throws Exception {
053        GitScmTestUtils.initRepo("src/test/resources/repository/", getRepositoryRoot(), getWorkingDirectory());
054    }
055
056    @Override
057    protected CheckOutScmResult checkOut(File workingDirectory, ScmRepository repository) throws Exception {
058        try {
059            return super.checkOut(workingDirectory, repository);
060        } finally {
061            GitScmTestUtils.setDefaultGitConfig(workingDirectory);
062        }
063    }
064
065    @Test
066    public void testUpToDatePush() throws Exception {
067        File checkedOutRepo = getWorkingCopy();
068
069        ScmRepository scmRepository = getScmManager().makeScmRepository(getScmUrl());
070        checkoutRepoInto(checkedOutRepo, scmRepository);
071
072        // Add a default user to the config
073        GitScmTestUtils.setDefaultGitConfig(checkedOutRepo);
074
075        CheckInScmResult result =
076                getScmManager().checkIn(scmRepository, new ScmFileSet(checkedOutRepo), "No change commit message");
077
078        assertResultIsSuccess(result);
079    }
080
081    @Test
082    public void testRejectedNonFastForwardPush() throws Exception {
083        File blockingRepo = PlexusJUnit4TestCase.getTestFile("target/scm-test/blocking-repo");
084        File rejectedRepo = PlexusJUnit4TestCase.getTestFile("target/scm-test/rejected-repo");
085
086        ScmRepository scmRepository = getScmManager().makeScmRepository(getScmUrl());
087        checkoutRepoInto(rejectedRepo, scmRepository);
088        checkoutRepoInto(blockingRepo, scmRepository);
089
090        // Add a default user to the config
091        GitScmTestUtils.setDefaultGitConfig(rejectedRepo);
092        GitScmTestUtils.setDefaultGitConfig(blockingRepo);
093
094        ScmFileSet blockingFileSet = createWorkspaceChange(rejectedRepo);
095
096        CommandParameters commandParameters = new CommandParameters();
097        commandParameters.setString(CommandParameter.MESSAGE, "Blocking commit");
098
099        CheckInScmResult blockingResult = getScmManager().checkIn(scmRepository, blockingFileSet, commandParameters);
100        assertResultIsSuccess(blockingResult);
101
102        ScmFileSet rejectedFileSet = createWorkspaceChange(blockingRepo);
103
104        commandParameters = new CommandParameters();
105        commandParameters.setString(CommandParameter.MESSAGE, "Rejected commit");
106
107        CheckInScmResult checkInScmResult = getScmManager().checkIn(scmRepository, rejectedFileSet, commandParameters);
108        assertFalse(
109                "check-in should have been rejected since fast forward was not possible", checkInScmResult.isSuccess());
110    }
111
112    @Test
113    public void testCommitWithRejectingPreCommitHook() throws Exception {
114        GitScmTestUtils.setupRejectAllCommitsPreCommitHook(getWorkingCopy());
115        GitScmTestUtils.setDefaultGitConfig(getWorkingCopy());
116        ScmFileSet addedFile = createWorkspaceChange(getWorkingCopy());
117        try {
118            CheckInScmResult result =
119                    getScmManager().checkIn(getScmRepository(), addedFile, "Commit with pre-commit hook");
120            assertFalse(
121                    "check-in should have been rejected since pre-push hook rejects all commits", result.isSuccess());
122        } catch (ScmException e) {
123            // some providers may use an exception to indicate a failed commit
124
125        }
126    }
127
128    @Test
129    public void testCommitNoVerify() throws Exception {
130        GitScmTestUtils.setupRejectAllCommitsPreCommitHook(getWorkingCopy());
131        GitScmTestUtils.setDefaultGitConfig(getWorkingCopy());
132        ScmFileSet addedFile = createWorkspaceChange(getWorkingCopy());
133        Path gitSettingsFile =
134                createTempFileFromClasspathResource("/git-settings-no-verify.xml", GitUtil.GIT_SETTINGS_FILENAME);
135        GitUtil.setSettingsDirectory(
136                gitSettingsFile.getParent().toFile()); // ensure that the settings are read from the .git directory
137        try {
138            CheckInScmResult result =
139                    getScmManager().checkIn(getScmRepository(), addedFile, "Commit with pre-commit hook");
140            assertResultIsSuccess(result);
141        } finally {
142            GitUtil.setSettingsDirectory(GitUtil.DEFAULT_SETTINGS_DIRECTORY); // reset to default settings directory
143            Files.delete(gitSettingsFile); // delete the temporary settings file
144            Files.delete(gitSettingsFile.getParent()); // delete the temporary settings directory
145        }
146    }
147
148    private CheckOutScmResult checkoutRepoInto(File workingCopy, ScmRepository scmRepository) throws Exception {
149        FileUtils.deleteDirectory(workingCopy);
150        workingCopy.mkdir();
151
152        CheckOutScmResult result = getScmManager().checkOut(scmRepository, new ScmFileSet(workingCopy), null);
153
154        assertResultIsSuccess(result);
155        return result;
156    }
157
158    private ScmFileSet createWorkspaceChange(File repo) throws IOException {
159        File beerFile = new File(repo.getAbsolutePath(), "beer.xml");
160        FileUtils.fileWrite(beerFile.getAbsolutePath(), "1 litre");
161        return new ScmFileSet(repo, beerFile.getName());
162    }
163
164    /**
165     * Creates a new file below a new temporary directory and copies the content of a classpath resource into it.
166     * The caller is responsible for deleting the temporary directory afterwards.
167     *
168     * @param resourceName from where to populate the file (relative to {@code clazz})
169     * @param fileName the file name to create below
170     * @return the newly created file
171     * @throws IOException in case of an error creating the file or copying the resource
172     */
173    private static Path createTempFileFromClasspathResource(String resourceName, String fileName) throws IOException {
174        Path tmpDirectory = Files.createTempDirectory("maven-scm-git-test-");
175        Path tmpFile = tmpDirectory.resolve(fileName);
176        try (InputStream inputStream = GitCheckInCommandTckTest.class.getResourceAsStream(resourceName)) {
177            if (inputStream == null) {
178                throw new IOException("Resource not found: " + resourceName);
179            }
180            Files.copy(inputStream, tmpFile, StandardCopyOption.REPLACE_EXISTING);
181        }
182        return tmpFile;
183    }
184}