br.com.ingenieux.jenkins.plugins.codecommit.CodeCommitURLHelper.java Source code

Java tutorial

Introduction

Here is the source code for br.com.ingenieux.jenkins.plugins.codecommit.CodeCommitURLHelper.java

Source

package br.com.ingenieux.jenkins.plugins.codecommit;

/*
 * Copyright (c) 2016 ingenieux Labs
 *
 * 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.
 */

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials;
import com.cloudbees.plugins.credentials.CredentialsNameProvider;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel;
import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.jenkinsci.plugins.gitclient.GitClient;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.security.auth.login.CredentialNotFoundException;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Extension;
import hudson.model.Item;
import hudson.plugins.git.GitException;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.extensions.GitSCMExtension;
import hudson.plugins.git.extensions.GitSCMExtensionDescriptor;
import hudson.security.ACL;

import static org.apache.commons.lang.StringUtils.isNotBlank;

/**
 * CodeCommit URL Helper
 */
public class CodeCommitURLHelper extends GitSCMExtension {
    private String credentialId;

    @DataBoundConstructor
    public CodeCommitURLHelper(String credentialId, String repositoryName) {
        this.credentialId = credentialId;
    }

    private static final class RepositoryUsernameReference {
        private final UsernamePasswordCredentialsImpl credential;

        private final String repositoryUrl;

        private final String repositoryName;

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;

            if (o == null || getClass() != o.getClass())
                return false;

            RepositoryUsernameReference that = (RepositoryUsernameReference) o;

            return new EqualsBuilder().append(repositoryName, that.repositoryName).isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37).append(repositoryName).toHashCode();
        }

        public RepositoryUsernameReference(String repositoryUrl, String repositoryName, String username,
                String password) {
            this.repositoryUrl = repositoryUrl;

            this.repositoryName = repositoryName;

            this.credential = new UsernamePasswordCredentialsImpl(CredentialsScope.USER, repositoryName,
                    "codecommit-" + repositoryName, username, password);
        }

        public UsernamePasswordCredentialsImpl getCredential() {
            return credential;
        }

        public String getRepositoryUrl() {
            return repositoryUrl;
        }

        public String getRepositoryName() {
            return repositoryName;
        }
    }

    @Override
    public GitClient decorate(GitSCM scm, GitClient git) throws IOException, InterruptedException, GitException {
        try {
            for (RepositoryUsernameReference r : fetchCodeCommitRepositoryNames(scm)) {
                git.addCredentials(r.getRepositoryUrl(), r.getCredential());
            }

            return git;
        } catch (Exception e) {
            throw new GitException("Meh", e);
        }
    }

    private static final Pattern PATTERN_CODECOMMIT_REPO = Pattern
            .compile("^https://git-codecommit.([^\\.]+).amazonaws.com/v1/repos/(.*)$");

    private Iterable<RepositoryUsernameReference> fetchCodeCommitRepositoryNames(GitSCM scm)
            throws CredentialNotFoundException {
        AWSCredentialsProvider credentials = new DefaultAWSCredentialsProviderChain();

        if (isNotBlank(credentialId)) {
            credentials = CredentialsFactory.getCredentials(credentialId);

            if (null == credentials)
                throw new CredentialNotFoundException(
                        "CredentialId '" + credentialId + "' specified but not found.");
        }

        Set<RepositoryUsernameReference> results = new LinkedHashSet<RepositoryUsernameReference>();

        for (RemoteConfig cfg : scm.getRepositories()) {
            for (URIish u : cfg.getURIs()) {
                final String repositoryUrl = u.toPrivateASCIIString();
                final Matcher m = PATTERN_CODECOMMIT_REPO.matcher(repositoryUrl);

                if (m.matches()) {
                    final String awsRegion = m.group(1);
                    final String repositoryName = m.group(2);

                    String usernamePassword = new CodeCommitRequestSigner(credentials, repositoryName, awsRegion,
                            new Date()).getPushUrl();

                    int lastIndex = usernamePassword.lastIndexOf(':');

                    String username = usernamePassword.substring(0, lastIndex);

                    String password = usernamePassword.substring(1 + lastIndex);

                    results.add(new RepositoryUsernameReference(repositoryUrl, repositoryName, username, password));
                }
            }
        }

        return results;
    }

    /**
     * Descriptor for {@link CodeCommitURLHelper}. Used as a singleton. The class is marked as
     * public so that it can be accessed from views.
     *
     * <p> See <tt>src/main/resources/hudson/plugins/hello_world/CodeCommitURLHelper/*.jelly</tt>
     * for the actual HTML fragment for the configuration screen.
     */
    @Extension // This indicates to Jenkins that this is an implementation of an extension point.
    public static final class DescriptorImpl extends GitSCMExtensionDescriptor {
        /**
         * In order to load the persisted global configuration, you have to call load() in the
         * constructor.
         */
        public DescriptorImpl() {
            load();
        }

        /**
         * This human readable name is used in the configuration screen.
         */
        public String getDisplayName() {
            return "AWS CodeCommit URL Helper";
        }

        public AbstractIdCredentialsListBoxModel<?, ?> doFillCredentialIdItems(@AncestorInPath Item owner) {
            if (owner == null || !owner.hasPermission(Item.CONFIGURE)) {
                return new AWSCredentialsListBoxModel();
            }

            List<AmazonWebServicesCredentials> creds = CredentialsProvider.lookupCredentials(
                    AmazonWebServicesCredentials.class, owner, ACL.SYSTEM,
                    Collections.<DomainRequirement>emptyList());

            return new AWSCredentialsListBoxModel().withEmptySelection().withAll(creds);
        }
    }

    public static class AWSCredentialsListBoxModel
            extends AbstractIdCredentialsListBoxModel<AWSCredentialsListBoxModel, AmazonWebServicesCredentials> {

        /**
         * {@inheritDoc}
         */
        @NonNull
        protected String describe(@NonNull AmazonWebServicesCredentials c) {
            return CredentialsNameProvider.name(c);
        }
    }
}