Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fc771b5
GCloud SDK auto-installer
ndeloof Jul 8, 2015
7889cd9
Use a temporary configuration dir
ndeloof Jul 8, 2015
44a8bca
decorate launcher to use the configured SDK installation
ndeloof Jul 8, 2015
9818b7a
configuring pom for hosting in jenkins
jrluis Jul 10, 2015
12166bf
add license
jrluis Jul 10, 2015
a7cd32f
Merge pull request #1 from ndeloof/master
jrluis Jul 10, 2015
01397ce
releasing version 0.0.1
jrluis Jul 10, 2015
8556034
releasing version 0.0.1
jrluis Jul 10, 2015
ea4f1a6
[maven-release-plugin] prepare release 0.0.1
jrluis Jul 10, 2015
4e11951
[maven-release-plugin] rollback the release of 0.0.1
jrluis Jul 10, 2015
710d714
[maven-release-plugin] prepare release 0.0.1
jrluis Jul 10, 2015
5d32a2d
[maven-release-plugin] prepare for next development iteration
jrluis Jul 10, 2015
7b0d1fa
as we delete configDir no need to cleanup/revoke
ndeloof Jul 15, 2015
6f11d53
simplify
ndeloof Jul 15, 2015
97dcdb0
activate to use the configured GCloudInstallation
ndeloof Jul 15, 2015
e55fbb3
bug
ndeloof Jul 15, 2015
9350abf
use SimpleBuildWrapper for workflow compliance
ndeloof Jul 15, 2015
ee58025
option to install additional components
ndeloof Jul 15, 2015
b0de5ef
Merge pull request #2 from ndeloof/master
jrluis Jul 20, 2015
711f399
new version of google credentials and fix gcloud path
ajcamilo Feb 27, 2017
92bcb35
Merge pull request #3 from ajcamilo/master
jrluis Feb 28, 2017
0829eb7
Restrict GCloudInstaller to GCloudInstallation types
Oct 24, 2017
bb04e5e
Add symbol definition to GCloudInstallation
Oct 24, 2017
06427a6
Use HTTPS URLs in pom.xml
daniel-beck-bot Oct 8, 2019
2eed88b
Remove unused imports
jhansche Jul 12, 2018
ae83b79
Support selecting the "(Default)" installation
jhansche Jul 12, 2018
d9c3ddd
Give better feedback when the SDK could not be selected
jhansche Jul 12, 2018
dbb60d7
Allow a blank GCloud service account to be selected.
jhansche Jul 12, 2018
3a32e09
Use google-oauth-plugin v0.8
jhansche Jun 18, 2019
e9e197f
Add Jenkinsfile for ci.jenkins.io
jhansche Jan 10, 2020
2cf8951
Update parent POM version to 2.7
jhansche Jan 10, 2020
fc78346
Fix findbugs errors
jhansche Jan 10, 2020
43bbb1b
[maven-release-plugin] prepare release gcloud-sdk-0.0.2
jhansche Jan 10, 2020
50dbebe
[maven-release-plugin] prepare for next development iteration
jhansche Jan 10, 2020
26dbd99
Explicitly depend on http-client-jackson2
jhansche Oct 22, 2019
d5c21a5
Merge pull request #10 from MeetMe/pr/use-jackson2
jhansche Jan 10, 2020
b170c07
[maven-release-plugin] prepare release gcloud-sdk-0.0.3
jhansche Jan 10, 2020
57bd900
[maven-release-plugin] prepare for next development iteration
jhansche Jan 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Build on ci.jenkins.io; see https://github.com/jenkins-infra/pipeline-library
buildPlugin()
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Byclosure

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
71 changes: 47 additions & 24 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,62 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.580.1</version>
<relativePath/>
<version>2.7</version>
<relativePath />
</parent>

<groupId>com.byclosure.jenkins.plugins</groupId>
<artifactId>gcloud-sdk</artifactId>
<version>1.0-SNAPSHOT</version>
<version>0.0.4-SNAPSHOT</version>
<packaging>hpi</packaging>

<properties>
<jenkins.version>2.60.3</jenkins.version>
<java.level>8</java.level>
<doclint>none</doclint>
</properties>

<name>GCloud SDK Plugin</name>
<description>GCloud SDK Plugin allows the invocation of the gcloud CLI as a job step.</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin</url>
<description>GCloud SDK Plugin allows users to invoke gcloud tools with jenkins credentials.</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/GCloud+SDK+Plugin</url>
<licenses>
<license>
<name>MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<!-- If you want this to appear on the wiki page:
<developers>

<developers>
<developer>
<id>bhacker</id>
<name>Bob Q. Hacker</name>
<email>bhacker@nowhere.net</email>
<id>jrluis</id>
<name>João Luís</name>
<email>jrluis@gmail.com</email>
</developer>
</developers>
-->
<!-- Assuming you want to host on @jenkinsci:
<scm>
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
<developerConnection>scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
<url>http://github.com/jenkinsci/${project.artifactId}-plugin</url>
</scm>
-->
</developers>

<scm>
<connection>scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git</connection>
<developerConnection>scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git</developerConnection>
<url>https://github.com/jenkinsci/gcloud-sdk-plugin</url>
<tag>HEAD</tag>
</scm>

<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>

<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>

<dependencies>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>access-modifier-suppressions</artifactId>
<version>1.16</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.24.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>google-oauth-plugin</artifactId>
<version>0.3</version>
<version>0.8</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.7</version>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,109 @@
package com.byclosure.jenkins.plugins.gcloud;

import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation;
import com.cloudbees.plugins.credentials.CredentialsMatcher;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import com.google.jenkins.plugins.credentials.domains.RequiresDomain;
import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildWrapper;
import hudson.model.Computer;
import hudson.model.Item;
import hudson.model.Node;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.security.ACL;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.util.ListBoxModel;
import jenkins.tasks.SimpleBuildWrapper;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import javax.annotation.CheckForNull;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;

@RequiresDomain(value = GCloudScopeRequirement.class)
public class GCloudBuildWrapper extends BuildWrapper {
public class GCloudBuildWrapper extends SimpleBuildWrapper {
private static final Logger LOGGER = Logger.getLogger(GCloudBuildWrapper.class.getName());

private final String installation;
private final String credentialsId;

@DataBoundConstructor
public GCloudBuildWrapper(String credentialsId) {
this.credentialsId = credentialsId;
}
public GCloudBuildWrapper(String installation, String credentialsId) {
this.installation = installation;
this.credentialsId = credentialsId;
}

@Override
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
final GCloudServiceAccount serviceAccount =
GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId);
@Override
public void setUp(Context context, Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException {

if (!serviceAccount.activate()) {
serviceAccount.cleanUp();
throw new InterruptedException("Couldn't activate GCloudServiceAccount");
}
GCloudInstallation sdk = getSDK();

if (sdk == null) {
throw new RuntimeException("Could not find a matching Google Cloud SDK installation: " + installation);
}

Computer computer = workspace.toComputer();
if (computer == null) throw new RuntimeException("Unable to get workspace node.");
Node node = computer.getNode();
if (node == null) throw new RuntimeException("Unable to get workspace node.");

return new Environment() {
@Override
public void buildEnvVars(Map<String, String> env) {
}
sdk = sdk.translate(node, initialEnvironment, listener);
final FilePath configDir = workspace.createTempDir("gcloud", "config");

@Override
public boolean tearDown(AbstractBuild build, final BuildListener listener) throws IOException, InterruptedException {
if (!serviceAccount.revoke()) {
serviceAccount.cleanUp();
return false;
}
final GCloudServiceAccount serviceAccount =
GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir);

serviceAccount.cleanUp();
return true;
}
if (serviceAccount != null) {
if (!serviceAccount.activate(sdk)) {
configDir.deleteRecursive();
throw new InterruptedException("Couldn't activate GCloudServiceAccount");
}

};
context.env("GOOGLE_APPLICATION_CREDENTIALS", serviceAccount.getKeyFile().getRemote());
}

context.env("CLOUDSDK_CONFIG", configDir.getRemote());

sdk.buildEnvVars(initialEnvironment);
for (Map.Entry<String, String> entry : initialEnvironment.entrySet()) {
context.env(entry.getKey(), entry.getValue());
}


context.setDisposer(new GCloudConfigDisposer(configDir));
}

public String getCredentialsId() {
public @CheckForNull GCloudInstallation getSDK() {
GCloudInstallation[] installations = GCloudInstallation.getInstallations();

if (installation.isEmpty() && installations.length > 0) {
return installations[0];
}

for (GCloudInstallation sdk : installations) {
if (installation.equals(sdk.getName())) return sdk;
}
return null;
}

public String getInstallation() {
return installation;
}

public String getCredentialsId() {
return credentialsId;
}

Expand All @@ -67,7 +115,7 @@ public DescriptorImpl() {

@Override
public String getDisplayName() {
return "GCloud authentication";
return "GCloud SDK authentication";
}

@Override
Expand All @@ -80,5 +128,38 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc
save();
return super.configure(req, formData);
}

public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item project,
@QueryParameter String serverAddress) {
if (project == null || !project.hasPermission(Item.CONFIGURE)) {
return new StandardListBoxModel();
}
return new StandardListBoxModel()
.withEmptySelection()
.withMatching(
MATCHER,
CredentialsProvider.lookupCredentials(GoogleRobotPrivateKeyCredentials.class,
project,
ACL.SYSTEM,
URIRequirementBuilder.fromUri(serverAddress).build()));
}

public static final CredentialsMatcher MATCHER = CredentialsMatchers.anyOf(CredentialsMatchers.instanceOf(GoogleRobotPrivateKeyCredentials.class));
}

private static class GCloudConfigDisposer extends Disposer {

private static final long serialVersionUID = 5723296082223871496L;

private final FilePath configDir;

public GCloudConfigDisposer(FilePath configDir) {
this.configDir = configDir;
}

@Override
public void tearDown(Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
configDir.deleteRecursive();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.google.jenkins.plugins.credentials.domains.RequiresDomain;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
Expand All @@ -17,9 +18,11 @@

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.logging.Logger;

@RequiresDomain(value = GCloudScopeRequirement.class)
public class GCloudSDKBuilder extends Builder {
private static final Logger LOGGER = Logger.getLogger(GCloudSDKBuilder.class.getName());

private final String command;

Expand All @@ -42,9 +45,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis
}

private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
EnvVars env = build.getEnvironment(listener);
String binariesPath = env.get("CLOUDSDK_DIR")+"/bin/";

int retCode = launcher.launch()
.pwd(build.getWorkspace())
.cmdAsSingleString("gcloud " + command)
.cmdAsSingleString(binariesPath + "gcloud " + command)
.envs(env)
.stdout(listener.getLogger())
.join();

Expand Down
Loading