diff --git a/README.md b/README.md index 03f1b7dcd..c00a5bfdf 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,6 @@ The following CI services are supported: - Google Cloud Build (GCB) - Jenkins - Travis -- Wercker For each of these services, a poller can be enabled (e.g. with `jenkins.enabled`) that will start monitoring new builds/pipelines/artifacts, caching them and submitting events to echo, thus supporting pipeline triggers. GCB is a bit different in that it doesn't poll and requires setting up [pubsub subscriptions](https://www.spinnaker.io/setup/ci/gcb/). diff --git a/igor-core/src/main/java/com/netflix/spinnaker/igor/model/BuildServiceProvider.java b/igor-core/src/main/java/com/netflix/spinnaker/igor/model/BuildServiceProvider.java index a81d8675c..9c64e4eda 100644 --- a/igor-core/src/main/java/com/netflix/spinnaker/igor/model/BuildServiceProvider.java +++ b/igor-core/src/main/java/com/netflix/spinnaker/igor/model/BuildServiceProvider.java @@ -23,6 +23,5 @@ public enum BuildServiceProvider { TRAVIS, CONCOURSE, GITLAB_CI, - WERCKER, GCB; } diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/build/InfoController.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/build/InfoController.groovy index 9e9f2ddd7..8c87b97b2 100644 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/build/InfoController.groovy +++ b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/build/InfoController.groovy @@ -22,7 +22,6 @@ import com.netflix.spinnaker.igor.jenkins.service.JenkinsService import com.netflix.spinnaker.igor.model.BuildServiceProvider import com.netflix.spinnaker.igor.service.BuildService import com.netflix.spinnaker.igor.service.BuildServices -import com.netflix.spinnaker.igor.wercker.WerckerService import com.netflix.spinnaker.kork.web.exceptions.NotFoundException import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired @@ -105,9 +104,6 @@ class InfoController { recursiveGetJobs(jenkinsService.jobs.list) return jobList - } else if (buildService instanceof WerckerService) { - WerckerService werckerService = (WerckerService) buildService - return werckerService.getJobs() } else { return buildCache.getJobNames(master) } diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerConfig.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerConfig.groovy deleted file mode 100644 index 1db2e990c..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerConfig.groovy +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.config - -import com.jakewharton.retrofit.Ok3Client -import com.netflix.spinnaker.config.DefaultServiceEndpoint -import com.netflix.spinnaker.config.okhttp3.OkHttpClientProvider -import com.netflix.spinnaker.igor.IgorConfigurationProperties -import com.netflix.spinnaker.igor.config.WerckerProperties.WerckerHost -import com.netflix.spinnaker.igor.service.BuildServices -import com.netflix.spinnaker.igor.wercker.WerckerCache -import com.netflix.spinnaker.igor.wercker.WerckerClient -import com.netflix.spinnaker.igor.wercker.WerckerService -import com.netflix.spinnaker.retrofit.Slf4jRetrofitLogger - -import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j -import okhttp3.OkHttpClient -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -import java.util.concurrent.TimeUnit - -import javax.validation.Valid - -import retrofit.Endpoints -import retrofit.RestAdapter - -@Configuration -@Slf4j -@CompileStatic -@ConditionalOnProperty("wercker.enabled") -@EnableConfigurationProperties(WerckerProperties) -class WerckerConfig { - @Bean - Map werckerMasters( - BuildServices buildServices, - WerckerCache cache, - IgorConfigurationProperties igorConfigurationProperties, - OkHttpClientProvider clientProvider, - @Valid WerckerProperties werckerProperties, - RestAdapter.LogLevel retrofitLogLevel) { - log.debug "creating werckerMasters" - Map werckerMasters = werckerProperties?.masters?.collectEntries { WerckerHost host -> - log.debug "bootstrapping Wercker ${host.address} as ${host.name}" - [(host.name): new WerckerService(host, cache, werckerClient(host, igorConfigurationProperties.getClient().timeout, clientProvider, retrofitLogLevel), host.permissions.build())] - } - - buildServices.addServices(werckerMasters) - werckerMasters - } - - static WerckerClient werckerClient(WerckerHost host, int timeout = 30000, OkHttpClientProvider clientProvider, RestAdapter.LogLevel retrofitLogLevel) { - OkHttpClient client = clientProvider.getClient(new DefaultServiceEndpoint(host.name, host.address, false)) - client = client.newBuilder().readTimeout(timeout, TimeUnit.MILLISECONDS).build() - return new RestAdapter.Builder() - .setLog(new Slf4jRetrofitLogger(WerckerService)) - .setLogLevel(retrofitLogLevel) - .setEndpoint(Endpoints.newFixedEndpoint(host.address)) - .setClient(new Ok3Client(client)) - .build() - .create(WerckerClient) - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerProperties.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerProperties.groovy deleted file mode 100644 index e087ba510..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/config/WerckerProperties.groovy +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.config - -import com.netflix.spinnaker.fiat.model.resources.Permissions -import groovy.transform.CompileStatic -import org.hibernate.validator.constraints.NotEmpty -import org.springframework.boot.context.properties.ConfigurationProperties - -import javax.validation.Valid - -/** - * Helper class to map masters in properties file into a validated property map - */ -@CompileStatic -@ConfigurationProperties(prefix = 'wercker') -class WerckerProperties implements BuildServerProperties { - @Valid - List masters - - static class WerckerHost implements BuildServerProperties.Host { - @NotEmpty - String name - - @NotEmpty - String address - - String user - - String token - - Integer itemUpperThreshold - - Permissions.Builder permissions = new Permissions.Builder() - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitor.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitor.groovy deleted file mode 100644 index 24eca6b7c..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitor.groovy +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.kork.discovery.DiscoveryStatusListener -import com.netflix.spinnaker.kork.dynamicconfig.DynamicConfigService -import com.netflix.spinnaker.security.AuthenticatedRequest -import org.springframework.scheduling.TaskScheduler - -import static com.netflix.spinnaker.igor.wercker.model.Run.finishedAtComparator -import static com.netflix.spinnaker.igor.wercker.model.Run.startedAtComparator -import static net.logstash.logback.argument.StructuredArguments.kv - -import com.netflix.spectator.api.Registry -import com.netflix.spinnaker.igor.IgorConfigurationProperties -import com.netflix.spinnaker.igor.build.model.GenericBuild -import com.netflix.spinnaker.igor.build.model.GenericProject -import com.netflix.spinnaker.igor.build.model.Result -import com.netflix.spinnaker.igor.config.WerckerProperties -import com.netflix.spinnaker.igor.history.EchoService -import com.netflix.spinnaker.igor.history.model.GenericBuildContent -import com.netflix.spinnaker.igor.history.model.GenericBuildEvent -import com.netflix.spinnaker.igor.model.BuildServiceProvider -import com.netflix.spinnaker.igor.polling.CommonPollingMonitor -import com.netflix.spinnaker.igor.polling.DeltaItem -import com.netflix.spinnaker.igor.polling.LockService -import com.netflix.spinnaker.igor.polling.PollContext -import com.netflix.spinnaker.igor.polling.PollingDelta -import com.netflix.spinnaker.igor.service.BuildServices -import com.netflix.spinnaker.igor.wercker.model.Run - -import groovy.time.TimeCategory - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.stereotype.Service - -import java.util.stream.Collectors - -import javax.annotation.PreDestroy - -import retrofit.RetrofitError - -/** - * Monitors new wercker runs - */ -@Service -@ConditionalOnProperty('wercker.enabled') -class WerckerBuildMonitor extends CommonPollingMonitor { - - private final WerckerCache cache - private final BuildServices buildServices - private final boolean pollingEnabled - private final Optional echoService - private final WerckerProperties werckerProperties - - @Autowired - WerckerBuildMonitor( - IgorConfigurationProperties properties, - Registry registry, - DynamicConfigService dynamicConfigService, - DiscoveryStatusListener discoveryStatusListener, - Optional < LockService > lockService, - WerckerCache cache, - BuildServices buildServices, - @Value('${wercker.polling.enabled:true}') boolean pollingEnabled, - Optional echoService, - WerckerProperties werckerProperties, - TaskScheduler scheduler) { - super(properties, registry, dynamicConfigService, discoveryStatusListener, lockService, scheduler) - this.cache = cache - this.buildServices = buildServices - this.pollingEnabled = pollingEnabled - this.echoService = echoService - this.werckerProperties = werckerProperties - } - - @Override - String getName() { - "WerckerBuildMonitor" - } - - @Override - boolean isInService() { - pollingEnabled && super.isInService() - } - - @Override - void poll(boolean sendEvents) { - long startTime = System.currentTimeMillis() - log.info "WerckerBuildMonitor Polling cycle started: ${new Date()}, echoService:${echoService.isPresent()} " - buildServices.getServiceNames(BuildServiceProvider.WERCKER).parallelStream().forEach( { master -> - pollSingle(new PollContext(master, !sendEvents)) - } - ) - log.info "WerckerBuildMonitor Polling cycle done in ${System.currentTimeMillis() - startTime}ms" - } - - /** - * Gets a list of pipelines for this master & processes runs between last poll stamp and a sliding upper bound stamp, - * the cursor will be used to advanced to the upper bound when all builds are completed in the commit phase. - */ - @Override - protected PipelinePollingDelta generateDelta(PollContext ctx) { - String master = ctx.partitionName - log.info("Checking for new builds for $master") - def startTime = System.currentTimeMillis() - - List delta = [] - - WerckerService werckerService = buildServices.getService(master) as WerckerService - long since = System.currentTimeMillis() - (Long.valueOf(getPollInterval() * 2 * 1000)) - try { - Map> runs = werckerService.getRunsSince(since) - runs.keySet().forEach( { pipeline -> - processRuns(werckerService, master, pipeline, delta, runs.get(pipeline)) - } ) - } catch (e) { - log.error("Error processing runs for Wercker[{}]", kv("master", master), e) - } - log.debug("Took ${System.currentTimeMillis() - startTime}ms to retrieve Wercker pipelines (master: {})", kv("master", master)) - return new PipelinePollingDelta(master: master, items: delta) - } - - Run getLastFinishedAt(List runs) { - return (runs && runs.size() > 0) ? Collections.max(runs, finishedAtComparator) : null - } - - Run getLastStartedAt(List runs) { - return Collections.max(runs, startedAtComparator) - } - - /** - * wercker.pipeline = project|job - * wercker.run = build - */ - private void processRuns( WerckerService werckerService, String master, String pipeline, - List delta, List runs) { - List allRuns = runs ?: werckerService.getBuilds(pipeline) - log.info "polling Wercker pipeline: ${pipeline} got ${allRuns.size()} runs" - if (allRuns.empty) { - log.debug("[{}:{}] has no runs skipping...", kv("master", master), kv("pipeline", pipeline)) - return - } - Run lastStartedAt = getLastStartedAt(allRuns) - try { - Long cursor = cache.getLastPollCycleTimestamp(master, pipeline) - //The last build/run - Long lastBuildStamp = lastStartedAt.startedAt.fastTime - Date upperBound = lastStartedAt.startedAt - if (cursor == lastBuildStamp) { - log.debug("[${master}:${pipeline}] is up to date. skipping") - return - } - cache.updateBuildNumbers(master, pipeline, allRuns) - List allBuilds = allRuns.findAll { it?.startedAt?.fastTime > cursor } - if (!cursor && !igorProperties.spinnaker.build.handleFirstBuilds) { - cache.setLastPollCycleTimestamp(master, pipeline, lastBuildStamp) - return - } - List currentlyBuilding = allBuilds.findAll { it.finishedAt == null } - //If there are multiple completed runs, use only the latest finished one - log.debug "allNewBuilds: ${allBuilds}" - Run lastFinished = getLastFinishedAt(allBuilds) - List completedBuilds = (lastFinished && lastFinished.finishedAt)? [lastFinished]: [] - log.debug("[${master}:${pipeline}] currentlyBuilding: ${currentlyBuilding}" ) - log.debug("[${master}:${pipeline}] completedBuilds: ${completedBuilds}" ) - cursor = cursor?:lastBuildStamp - Date lowerBound = new Date(cursor) - if (!igorProperties.spinnaker.build.processBuildsOlderThanLookBackWindow) { - completedBuilds = onlyInLookBackWindow(completedBuilds) - } - delta.add(new PipelineDelta( - cursor: cursor, - name: pipeline, - lastBuildStamp: lastBuildStamp, - upperBound: upperBound, - lowerBound: lowerBound, - completedBuilds: completedBuilds, - runningBuilds: currentlyBuilding - )) - } catch (e) { - log.error("Error processing runs for [{}:{}]", kv("master", master), kv("pipeline", pipeline), e) - if (e.cause instanceof RetrofitError) { - def re = (RetrofitError) e.cause - log.error("Error communicating with Wercker for [{}:{}]: {}", kv("master", master), kv("pipeline", pipeline), kv("url", re.url), re) - } - } - } - - private List onlyInLookBackWindow(List builds) { - use(TimeCategory) { - def offsetSeconds = pollInterval.seconds - def lookBackWindowMins = igorProperties.spinnaker.build.lookBackWindowMins.minutes - Date lookBackDate = (offsetSeconds + lookBackWindowMins).ago - return builds.stream().filter({ - Date buildEndDate = it.finishedAt - return buildEndDate.after(lookBackDate) - }).collect(Collectors.toList()) - } - } - - private GenericBuild toBuild(String master, String pipeline, Run run) { - Result res = (run.finishedAt == null) ? Result.BUILDING : (run.result.equals("passed")? Result.SUCCESS : Result.FAILURE) - return new GenericBuild ( - building: (run.finishedAt == null), - result: res, - number: cache.getBuildNumber(master, pipeline, run.id), - timestamp: run.startedAt.fastTime as String, - id: run.id, - url: run.url - ) - } - - @Override - protected void commitDelta(PipelinePollingDelta delta, boolean sendEvents) { - String master = delta.master - delta.items.parallelStream().forEach { pipeline -> - //job = Wercker pipeline (org/app/pipeline) - // post event for latest finished run - pipeline.completedBuilds.forEach { run -> - //build = Wercker run - Boolean eventPosted = cache.getEventPosted(master, pipeline.name, run.id) - GenericBuild build = toBuild(master, pipeline.name, run) - if (!eventPosted && sendEvents) { - log.debug("[${master}:${pipeline.name}]:${build.id} event posted") - if(postEvent(new GenericProject(pipeline.name, build), master)) { - cache.setEventPosted(master, pipeline.name, run.id) - } - } - } - - // advance cursor when all builds have completed in the interval - if (pipeline.runningBuilds.isEmpty()) { - log.info("[{}:{}] has no other builds between [${pipeline.lowerBound} - ${pipeline.upperBound}], advancing cursor to ${pipeline.lastBuildStamp}", kv("master", master), kv("pipeline", pipeline.name)) - cache.pruneOldMarkers(master, pipeline.name, pipeline.cursor) - cache.setLastPollCycleTimestamp(master, pipeline.name, pipeline.lastBuildStamp) - } - } - } - - @Override - protected Integer getPartitionUpperThreshold(String partition) { - return werckerProperties.masters.find { partition == it.name }?.itemUpperThreshold - } - - private boolean postEvent(GenericProject project, String master) { - if (!echoService.isPresent()) { - log.warn("Cannot send build notification: Echo is not configured") - registry.counter(missedNotificationId.withTag("monitor", getName())).increment() - return false - } - AuthenticatedRequest.allowAnonymous { - echoService.get().postEvent(new GenericBuildEvent(content: new GenericBuildContent(project: project, master: master, type: "wercker"))) - } - return true - } - - private static class PipelinePollingDelta implements PollingDelta { - String master - List items - } - - private static class PipelineDelta implements DeltaItem { - Long cursor - String name - Long lastBuildStamp - Date lowerBound - Date upperBound - List completedBuilds - List runningBuilds - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerCache.java b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerCache.java deleted file mode 100644 index 37a562e1c..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerCache.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker; - -import static com.netflix.spinnaker.igor.wercker.model.Run.startedAtComparator; - -import com.netflix.spinnaker.igor.IgorConfigurationProperties; -import com.netflix.spinnaker.igor.wercker.model.Run; -import com.netflix.spinnaker.kork.jedis.RedisClientDelegate; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** Shared cache of build details for jenkins */ -@Service -public class WerckerCache { - - private static final String POLL_STAMP = "lastPollCycleTimestamp"; - private static final String PIPELINE_ID = "pipelineId"; - private static final String PIPELINE_NAME = "pipelineName"; - - private final RedisClientDelegate redisClientDelegate; - private final IgorConfigurationProperties igorConfigurationProperties; - - @Autowired - public WerckerCache( - RedisClientDelegate redisClientDelegate, - IgorConfigurationProperties igorConfigurationProperties) { - this.redisClientDelegate = redisClientDelegate; - this.igorConfigurationProperties = igorConfigurationProperties; - } - - public void setLastPollCycleTimestamp(String master, String pipeline, Long timestamp) { - String key = makeKey(master, pipeline); - redisClientDelegate.withCommandsClient( - c -> { - c.hset(key, POLL_STAMP, Long.toString(timestamp)); - }); - } - - public Long getLastPollCycleTimestamp(String master, String pipeline) { - return redisClientDelegate.withCommandsClient( - c -> { - String ts = c.hget(makeKey(master, pipeline), POLL_STAMP); - return ts == null ? null : Long.parseLong(ts); - }); - } - - public String getPipelineID(String master, String pipeline) { - return redisClientDelegate.withCommandsClient( - c -> { - return c.hget(makeKey(master, pipeline), PIPELINE_ID); - }); - } - - public String getPipelineName(String master, String id) { - return redisClientDelegate.withCommandsClient( - c -> { - return c.hget(nameKey(master, id), PIPELINE_NAME); - }); - } - - public void setPipelineID(String master, String pipeline, String id) { - String key = makeKey(master, pipeline); - redisClientDelegate.withCommandsClient( - c -> { - c.hset(key, PIPELINE_ID, id); - }); - - String nameKey = nameKey(master, id); - redisClientDelegate.withCommandsClient( - c -> { - c.hset(nameKey, PIPELINE_NAME, pipeline); - }); - } - - public String getRunID(String master, String pipeline, final int buildNumber) { - String key = makeKey(master, pipeline) + ":runs"; - final Map existing = - redisClientDelegate.withCommandsClient( - c -> { - if (!c.exists(key)) { - return null; - } - return c.hgetAll(key); - }); - String build = Integer.toString(buildNumber); - for (Entry entry : existing.entrySet()) { - if (entry.getValue().equals(build)) { - return entry.getKey(); - } - } - return null; - } - - /** - * Creates entries in Redis for each run in the runs list (except if the run id already exists) - * and generates build numbers for each run id (ordered by startedAt date) - * - * @param master - * @param appAndPipelineName - * @param runs - * @return a map containing the generated build numbers for each run created, keyed by run id - */ - public Map updateBuildNumbers( - String master, String appAndPipelineName, List runs) { - String key = makeKey(master, appAndPipelineName) + ":runs"; - final Map existing = - redisClientDelegate.withCommandsClient( - c -> { - if (!c.exists(key)) { - return null; - } - return c.hgetAll(key); - }); - List newRuns = runs; - if (existing != null && existing.size() > 0) { - newRuns = - runs.stream() - .filter(run -> !existing.containsKey(run.getId())) - .collect(Collectors.toList()); - } - Map runIdToBuildNumber = new HashMap<>(); - int startNumber = (existing == null || existing.size() == 0) ? 0 : existing.size(); - newRuns.sort(startedAtComparator); - for (int i = 0; i < newRuns.size(); i++) { - int buildNum = startNumber + i; - setBuildNumber(master, appAndPipelineName, newRuns.get(i).getId(), buildNum); - runIdToBuildNumber.put(newRuns.get(i).getId(), buildNum); - } - return runIdToBuildNumber; - } - - public void setBuildNumber(String master, String pipeline, String runID, int number) { - String key = makeKey(master, pipeline) + ":runs"; - redisClientDelegate.withCommandsClient( - c -> { - c.hset(key, runID, Integer.toString(number)); - }); - } - - public Long getBuildNumber(String master, String pipeline, String runID) { - return redisClientDelegate.withCommandsClient( - c -> { - String ts = c.hget(makeKey(master, pipeline) + ":runs", runID); - return ts == null ? null : Long.parseLong(ts); - }); - } - - public Boolean getEventPosted(String master, String job, String runID) { - String key = makeEventsKey(master, job); - return redisClientDelegate.withCommandsClient(c -> c.hget(key, runID) != null); - } - - public void setEventPosted(String master, String job, String runID) { - String key = makeEventsKey(master, job); - redisClientDelegate.withCommandsClient( - c -> { - c.hset(key, runID, "POSTED"); - }); - } - - public void pruneOldMarkers(String master, String job, Long cursor) { - remove(master, job); - redisClientDelegate.withCommandsClient( - c -> { - c.del(makeEventsKey(master, job)); - }); - } - - public void remove(String master, String job) { - redisClientDelegate.withCommandsClient( - c -> { - c.del(makeKey(master, job)); - }); - } - - private String makeEventsKey(String master, String job) { - return makeKey(master, job) + ":" + POLL_STAMP + ":events"; - } - - private String makeKey(String master, String job) { - return prefix() + ":" + master + ":" + job.toUpperCase() + ":" + job; - } - - private String nameKey(String master, String pipelineId) { - return prefix() + ":" + master + ":all_pipelines:" + pipelineId; - } - - private String prefix() { - return igorConfigurationProperties.getSpinnaker().getJedis().getPrefix() + "_wercker"; - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerClient.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerClient.groovy deleted file mode 100644 index 73f25ad2c..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerClient.groovy +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.igor.wercker.model.Application -import com.netflix.spinnaker.igor.wercker.model.Pipeline -import com.netflix.spinnaker.igor.wercker.model.Run -import com.netflix.spinnaker.igor.wercker.model.RunPayload -import com.netflix.spinnaker.igor.wercker.model.Workflow - -import retrofit.client.Response -import retrofit.http.* - -/** - * Interface for interacting with a Wercker service using retrofit - */ -interface WerckerClient { - - @GET('/api/v3/applications/{owner}') - List getApplicationsByOwner( - @Header('Authorization') String authHeader, - @Path('owner') owner) - - @GET('/api/spinnaker/v1/applications') - List getApplications(@Header('Authorization') String authHeader, @Query('limit') int limit) - - @GET('/api/v3/runs') - List getRunsForApplication( - @Header('Authorization') String authHeader, - @Query('applicationId') String applicationId) - - @GET('/api/v3/runs') - List getRunsForPipeline( - @Header('Authorization') String authHeader, - @Query('pipelineId') String pipelineId) - - @GET('/api/spinnaker/v1/runs') - List getRunsSince( - @Header('Authorization') String authHeader, - @Query('branch') String branch, - @Query('pipelineIds') List pipelineIds, - @Query('limit') int limit, - @Query('since') long since) - - @GET('/api/v3/workflows') - List getWorkflowsForApplication( - @Header('Authorization') String authHeader, - @Query('applicationId') String applicationId) - - @GET('/api/v3/applications/{username}/{appName}/pipelines') - List getPipelinesForApplication( - @Header('Authorization') String authHeader, - @Path('username') username, - @Path('appName') appName) - - @GET('/api/v3/pipelines/{pipelineId}') - Pipeline getPipeline( - @Header('Authorization') String authHeader, - @Path('pipelineId') String pipelineId) - - @POST('/api/v3/runs') - Map triggerBuild( - @Header('Authorization') String authHeader, - @Body RunPayload runPayload - ) - - @GET('/api/v3/runs/{runId}') - Run getRunById(@Header('Authorization') String authHeader, - @Path('runId') String runId) - - @PUT('/api/v3/runs/{runId}/abort') - Response abortRun(@Header('Authorization') String authHeader, - @Path('runId') String runId, - @Body Map body) -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerService.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerService.groovy deleted file mode 100644 index 380206e5c..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/WerckerService.groovy +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.fiat.model.resources.Permissions -import com.netflix.spinnaker.igor.build.BuildController -import com.netflix.spinnaker.igor.build.model.GenericBuild -import com.netflix.spinnaker.igor.build.model.GenericGitRevision -import com.netflix.spinnaker.igor.build.model.GenericJobConfiguration -import com.netflix.spinnaker.igor.build.model.JobConfiguration -import com.netflix.spinnaker.igor.build.model.Result -import com.netflix.spinnaker.igor.config.WerckerProperties.WerckerHost -import com.netflix.spinnaker.igor.exceptions.BuildJobError -import com.netflix.spinnaker.igor.model.BuildServiceProvider -import com.netflix.spinnaker.igor.service.BuildOperations -import com.netflix.spinnaker.igor.wercker.model.Application -import com.netflix.spinnaker.igor.wercker.model.Pipeline -import com.netflix.spinnaker.igor.wercker.model.QualifiedPipelineName -import com.netflix.spinnaker.igor.wercker.model.Run -import com.netflix.spinnaker.igor.wercker.model.RunPayload -import groovy.util.logging.Slf4j -import retrofit.RetrofitError -import retrofit.client.Response -import retrofit.mime.TypedByteArray - -import static com.netflix.spinnaker.igor.model.BuildServiceProvider.WERCKER -import static net.logstash.logback.argument.StructuredArguments.kv - -@Slf4j -class WerckerService implements BuildOperations { - - String groupKey - WerckerClient werckerClient - String user - String token - String authHeaderValue - String address - String master - WerckerCache cache - final Permissions permissions - - private static String branch = 'master' - private static limit = 300 - - WerckerService(WerckerHost wercker, WerckerCache cache, WerckerClient werckerClient, Permissions permissions) { - this.groupKey = wercker.name - this.werckerClient = werckerClient - this.user = wercker.user - this.cache = cache - this.address = address - this.master = wercker.name - this.setToken(token) - this.address = wercker.address - this.setToken(wercker.token) - this.permissions = permissions - } - - @Override - String getName() { - this.groupKey - } -/** - * Custom setter for token, in order to re-set the authHeaderValue - * @param token - * @return - */ - void setToken(String token) { - this.authHeaderValue = 'Bearer ' + token - } - - @Override - BuildServiceProvider getBuildServiceProvider() { - return WERCKER - } - - @Override - List getGenericGitRevisions(final String job, final GenericBuild build) { - return null - } - - @Override - GenericBuild getGenericBuild(final String job, final int buildNumber) { - QualifiedPipelineName qPipeline = QualifiedPipelineName.of(job) - String runId = cache.getRunID(groupKey, job, buildNumber) - if (runId == null) { - throw new BuildJobError( - "Could not find build number ${buildNumber} for job ${job} - no matching run ID!") - } - Run run = getRunById(runId) - String addr = address.endsWith("/") ? address.substring(0, address.length()-1) : address - - GenericBuild genericBuild = new GenericBuild() - genericBuild.name = job - genericBuild.building = true - genericBuild.fullDisplayName = "Wercker Job " + job + " [" + buildNumber + "]" - genericBuild.number = buildNumber - genericBuild.building = (run.finishedAt == null) - genericBuild.fullDisplayName = "Wercker Job " + job + " [" + runId + "]" - //The API URL: address + "api/v3/runs/" + cache.getRunID(groupKey, job, buildNumber) - genericBuild.url = String.join("/", addr, qPipeline.ownerName, qPipeline.appName, "runs", - qPipeline.pipelineName, runId) - genericBuild.result = mapRunToResult(run) - - return genericBuild - } - - Result mapRunToResult(final Run run) { - if (run.finishedAt == null) return Result.BUILDING - if ("notstarted".equals(run.status)) return Result.NOT_BUILT - switch (run.result) { - case "passed": - return Result.SUCCESS - break - case "aborted": - return Result.ABORTED - break - case "failed": - return Result.FAILURE - break - } - return Result.UNSTABLE - } - - Response stopRunningBuild (String appAndPipelineName, Integer buildNumber){ - String runId = cache.getRunID(groupKey, appAndPipelineName, buildNumber) - if (runId == null) { - log.warn("Could not cancel build number {} for job {} - no matching run ID!", - kv("buildNumber", buildNumber), kv("job", appAndPipelineName)) - return - } - log.info("Aborting Wercker run id {}", kv("runId", runId)) - return abortRun(authHeaderValue, runId, [:]) - } - - @Override - int triggerBuildWithParameters(final String appAndPipelineName, final Map queryParameters) { - QualifiedPipelineName qPipeline = QualifiedPipelineName.of(appAndPipelineName) - String org = qPipeline.ownerName - String appName = qPipeline.appName - String pipelineName = qPipeline.pipelineName - - List pipelines = getPipelines(org, appName) - List pnames = pipelines.collect { it.name + "|" +it.pipelineName + "|" + it.id } - log.debug "triggerBuildWithParameters pipelines: ${pnames}" - Pipeline pipeline = pipelines.find {p -> pipelineName.equals(p.name)} - if (pipeline) { - log.info("Triggering run for pipeline {} with id {}", - kv("pipelineName", pipelineName), kv("pipelineId", pipeline.id)) - try { - Map runInfo = triggerBuild(new RunPayload(pipeline.id, 'Triggered from Spinnaker')) - //TODO desagar the triggerBuild call above itself returns a Run, but the createdAt date - //is not in ISO8601 format, and parsing fails. The following is a temporary - //workaround - the getRunById call below gets the same Run object but Wercker - //returns the date in the ISO8601 format for this case. - Run run = getRunById(runInfo.get('id')) - - //Create an entry in the WerckerCache for this new run. This will also generate - //an integer build number for the run - Map runIdBuildNumbers = cache.updateBuildNumbers( - master, appAndPipelineName, Collections.singletonList(run)) - - log.info("Triggered run {} at URL {} with build number {}", - kv("runId", run.id), kv("url", run.url), - kv("buildNumber", runIdBuildNumbers.get(run.id))) - - //return the integer build number for this run id - return runIdBuildNumbers.get(run.id) - } catch (RetrofitError e) { - def body = e.getResponse().getBody() - String wkrMsg - if (body instanceof TypedByteArray) { - wkrMsg = new String(((retrofit.mime.TypedByteArray) body).getBytes()) - } else { - wkrMsg = body.in().text - } - log.error("Failed to trigger build for pipeline {}. {}", kv("pipelineName", pipelineName), kv("errMsg", wkrMsg)) - throw new BuildJobError( - "Failed to trigger build for pipeline ${pipelineName}! Error from Wercker is: ${wkrMsg}") - } - } else { - throw new BuildController.InvalidJobParameterException( - "Could not retrieve pipeline ${pipelineName} for application ${appName} from Wercker!") - } - } - - /** - * Returns List of all Wercker jobs in the format of type/org/app/pipeline - */ - List getJobs() { - List jobs = [] - List apps = getApplications() - long start = System.currentTimeMillis() - apps.each { app -> - try { - List pipelines = app.pipelines ?: [] - jobs.addAll( pipelines.collect { - it.type + QualifiedPipelineName.SPLITOR + - new QualifiedPipelineName(app.owner.name, app.name, it.name).toString() - } ) - } catch(retrofit.RetrofitError err) { - log.error "Error getting pipelines for ${app.owner.name } ${app.name} ${err}" - } - } - log.debug "getPipelines: ${jobs.size()} pipelines in ${System.currentTimeMillis() - start}ms" - return jobs - } - - List getApplications() { - return werckerClient.getApplications(authHeaderValue, limit) - } - - List getPipelines(String org, String app) { - return werckerClient.getPipelinesForApplication(authHeaderValue, org, app) - } - - Run getRunById(String runId) { - return werckerClient.getRunById(authHeaderValue, runId) - } - - Response abortRun(String runId, Map body) { - return werckerClient.abortRun(authHeaderValue, runId, body) - } - - List getRunsSince(String branch, List pipelineIds, int limit, long since) { - return werckerClient.getRunsSince(authHeaderValue, branch, pipelineIds, limit, since) - } - - List getRunsForPipeline(String pipelineId) { - return werckerClient.getRunsForPipeline(authHeaderValue, pipelineId) - } - - Pipeline getPipeline(String pipelineId) { - return werckerClient.getPipeline(authHeaderValue, pipelineId) - } - - Map triggerBuild(RunPayload runPayload) { - return werckerClient.triggerBuild(authHeaderValue, runPayload) - } - - /** - * A CommandKey should be unique per group (to ensure broken circuits do not span Wercker masters) - */ - private String buildCommandKey(String id) { - return "${groupKey}-${id}" - } - - List getBuilds(String appAndPipelineName) { - String pipelineId = getPipelineId(appAndPipelineName) - log.debug "getBuildList for ${groupKey} ${appAndPipelineName} ${pipelineId}" - return pipelineId? getRunsForPipeline(pipelineId) : [] - } - - String pipelineKey(Run run, Map pipelineKeys) { - if (run.pipelineId) { - return pipelineKeys ? pipelineKeys.get(run.pipelineId) : getPipelineName(run.pipelineId) - } else { - return new QualifiedPipelineName( - run.getApplication().owner.name, run.getApplication().name, run.getPipeline().name) - .toString() - } - } - - String getPipelineId(String appAndPipelineName) { - QualifiedPipelineName qPipeline = QualifiedPipelineName.of(appAndPipelineName) - String pipelineId = cache.getPipelineID(groupKey, appAndPipelineName) - if (pipelineId == null) { - try { - List pipelines = getPipelines(qPipeline.ownerName, qPipeline.appName) - Pipeline matchingPipeline = pipelines.find { - pipeline -> qPipeline.pipelineName == pipeline.name - } - if (matchingPipeline) { - pipelineId = matchingPipeline.id - cache.setPipelineID(groupKey, appAndPipelineName, pipelineId) - } - } catch(retrofit.RetrofitError err) { - log.info "Error getting pipelines for ${qPipeline.ownerName} ${qPipeline.appName} ${err} ${err.getClass()}" - } - } - return pipelineId - } - - String getPipelineName(String pipelineId) { - String name = cache.getPipelineName(groupKey, pipelineId) - if (name == null) { - try { - Pipeline pipeline = getPipeline(pipelineId) - if (pipeline && pipeline.application && pipeline.application.owner) { - name = new QualifiedPipelineName( - pipeline.application.owner.name, - pipeline.application.name, - pipeline.name) - .toString() - cache.setPipelineID(groupKey, name, pipelineId) - } - } catch(retrofit.RetrofitError err) { - log.info "Error getting pipelines for ${owner} ${appName} ${err} ${err.getClass()}" - } - } - return name - } - - Map> getRunsSince(Set pipelines, long since) { - long start = System.currentTimeMillis() - Map pipelineKeys = pipelines.collectEntries { [(getPipelineId(it)) : (it)] } - List pids = pipelineKeys.keySet().asList() - List allRuns = getRunsSince(branch, pids, limit, since) - log.debug "getRunsSince for pipelines:${pipelines} : ${allRuns.size()} runs in ${System.currentTimeMillis() - start}ms!!" - return groupRunsByPipeline(allRuns, pipelineKeys) - } - - Map> getRunsSince(long since) { - long start = System.currentTimeMillis() - List allRuns = getRunsSince(branch, [], limit, since) - log.debug "getRunsSince ${since} : ${allRuns.size()} runs in ${System.currentTimeMillis() - start}ms!!" - return groupRunsByPipeline(allRuns, null) - } - - private Map> groupRunsByPipeline(List allRuns, Map pipelineKeys) { - Map> pipelineRuns = [:] - allRuns.forEach({run -> - run.startedAt = run.startedAt ?: run.createdAt - }) - return allRuns.groupBy {run -> - pipelineKey(run, pipelineKeys) - } - } - - //TODO investigate if Wercker needs the JobConfig implementation - @Override - JobConfiguration getJobConfig(String jobName) { - return new GenericJobConfiguration('WerckerPipeline ' + jobName, jobName) - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Application.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Application.groovy deleted file mode 100644 index 121e54ee0..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Application.groovy +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -import groovy.transform.ToString - -/** - * Represents a Wercker application - */ -@ToString -class Application { - String id - String url - String name - Owner owner - String privacy - List pipelines -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Owner.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Owner.groovy deleted file mode 100644 index 67feb5019..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Owner.groovy +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -class Owner { - String name - String type - String userId - OwnerMetadata meta - - static class OwnerMetadata { - String username - String type - boolean werckerEmployee - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Pipeline.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Pipeline.groovy deleted file mode 100644 index e8c5cf902..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Pipeline.groovy +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -import groovy.transform.ToString - -/** - * Represents a Wercker Pipeline - */ -@ToString -class Pipeline { - String id - String url - String name - String permissions - String pipelineName //This is the name in the wercker.yml - boolean setScmProviderStatus - String type - Application application -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/QualifiedPipelineName.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/QualifiedPipelineName.groovy deleted file mode 100644 index 22eddf0fb..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/QualifiedPipelineName.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -class QualifiedPipelineName { - static String SPLITOR = "/"; - - String ownerName; - String appName; - String pipelineName; - - QualifiedPipelineName(String ownerName, String appName, String pipelineName) { - this.ownerName = ownerName; - this.appName = appName; - this.pipelineName = pipelineName; - } - - String toString() { - return this.ownerName + SPLITOR + this.appName + SPLITOR + this.pipelineName - } - - static QualifiedPipelineName of(String qualifiedPipelineName) { - String[] split = qualifiedPipelineName.split(SPLITOR) - return new QualifiedPipelineName(split[0], split[1], split[2]) - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Run.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Run.groovy deleted file mode 100644 index 824644c17..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Run.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -import static java.util.Comparator.comparing -import static java.util.Comparator.naturalOrder -import static java.util.Comparator.nullsFirst - -import groovy.transform.ToString - -/** - * Represents a Wercker Run - */ -@ToString -class Run { - String id - String url - String branch - String commitHash - Date createdAt - Date finishedAt - Date startedAt - - String message - int progress - String result - String status - - Owner user - String pipelineId - Pipeline pipeline - Application application - - static final public Comparator startedAtComparator = - comparing({r -> r.startedAt?: r.createdAt}, nullsFirst(naturalOrder())) - - static final public Comparator finishedAtComparator = - comparing({r -> r.finishedAt}, nullsFirst(naturalOrder())) -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/RunPayload.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/RunPayload.groovy deleted file mode 100644 index 9e70e5445..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/RunPayload.groovy +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -class RunPayload { - String pipelineId - String message - - RunPayload(final String pipelineId, final String message) { - this.pipelineId = pipelineId - this.message = message - } -} diff --git a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Workflow.groovy b/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Workflow.groovy deleted file mode 100644 index 2ca79107a..000000000 --- a/igor-web/src/main/groovy/com/netflix/spinnaker/igor/wercker/model/Workflow.groovy +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker.model - -class Workflow { - String url - WorkflowData data - - static class WorkflowData { - String branch - String commitHash - String message - } -} diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/build/InfoControllerSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/build/InfoControllerSpec.groovy index afd6511d1..4cfbe252e 100644 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/build/InfoControllerSpec.groovy +++ b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/build/InfoControllerSpec.groovy @@ -26,7 +26,6 @@ import com.netflix.spinnaker.igor.model.BuildServiceProvider import com.netflix.spinnaker.igor.service.BuildOperations import com.netflix.spinnaker.igor.service.BuildServices import com.netflix.spinnaker.igor.travis.service.TravisService -import com.netflix.spinnaker.igor.wercker.WerckerService import com.squareup.okhttp.mockwebserver.MockResponse import com.squareup.okhttp.mockwebserver.MockWebServer import groovy.json.JsonSlurper @@ -290,23 +289,6 @@ class InfoControllerSpec extends Specification { } - void 'is able to get jobs for a wercker master'() { - given: - def werckerJob = 'myOrg/myApp/myTarget' - WerckerService werckerService = Stub(WerckerService) - createMocks(['wercker-master': werckerService]) - - when: - MockHttpServletResponse response = mockMvc.perform(get('/jobs/wercker-master') - .accept(MediaType.APPLICATION_JSON)).andReturn().response - - then: - werckerService.getBuildServiceProvider() >> BuildServiceProvider.WERCKER - werckerService.getJobs() >> [werckerJob] - response.contentAsString == '["' + werckerJob + '"]' - - } - private void setResponse(String body) { server.enqueue( new MockResponse() diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/QualifiedPipelineNameSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/QualifiedPipelineNameSpec.groovy deleted file mode 100644 index 8be92e13b..000000000 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/QualifiedPipelineNameSpec.groovy +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.igor.wercker.model.QualifiedPipelineName -import spock.lang.Specification - -class QualifiedPipelineNameSpec extends Specification { - void 'serializeDeserialize'() { - setup: - String origName = 'owner1/someApp/aPipeline' - QualifiedPipelineName qp = QualifiedPipelineName.of(origName) - String qpName = qp.toString() - - expect: - origName.equals(qpName) - qp.ownerName.equals('owner1') - qp.appName.equals('someApp') - qp.pipelineName.equals('aPipeline') - } - -} diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitorSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitorSpec.groovy deleted file mode 100644 index 6469a136f..000000000 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerBuildMonitorSpec.groovy +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spectator.api.NoopRegistry -import com.netflix.spinnaker.fiat.model.resources.Permissions -import com.netflix.spinnaker.igor.IgorConfigurationProperties -import com.netflix.spinnaker.igor.config.WerckerProperties -import com.netflix.spinnaker.igor.config.WerckerProperties.WerckerHost -import com.netflix.spinnaker.igor.history.EchoService -import com.netflix.spinnaker.igor.model.BuildServiceProvider -import com.netflix.spinnaker.igor.polling.PollContext -import com.netflix.spinnaker.igor.service.BuildServices -import com.netflix.spinnaker.igor.wercker.model.Application -import com.netflix.spinnaker.igor.wercker.model.Owner -import com.netflix.spinnaker.igor.wercker.model.Pipeline -import com.netflix.spinnaker.igor.wercker.model.Run -import com.netflix.spinnaker.kork.discovery.DiscoveryStatusListener -import com.netflix.spinnaker.kork.dynamicconfig.DynamicConfigService -import org.springframework.scheduling.TaskScheduler -import spock.lang.Specification - -class WerckerBuildMonitorSpec extends Specification { - - WerckerCache cache = Mock(WerckerCache) - WerckerBuildMonitor monitor - EchoService echoService = Mock(EchoService) - WerckerClient client - WerckerService mockService = Mock(WerckerService) - WerckerService werckerService - String werckerDev = 'https://dev.wercker.com/' - String master = 'WerckerTestMaster' - - void setup() { - client = Mock(WerckerClient) - werckerService = new WerckerService( - new WerckerHost(name: master, address: werckerDev), cache, client, Permissions.EMPTY) - } - - def MASTER = 'MASTER' - - BuildServices mockBuildServices() { - BuildServices buildServices = new BuildServices() - buildServices.addServices([MASTER: mockService]) - return buildServices - } - - void 'no finished run'() { - given: - BuildServices buildServices = mockBuildServices() - - long now = System.currentTimeMillis(); - List runs1 = [ - new Run(id:"b", startedAt: new Date(now-10)), - new Run(id:"a", startedAt: new Date(now-11)), - new Run(id:"init", startedAt: new Date(now-12)), - ] - monitor = monitor(buildServices) - mockService.getRunsSince(_) >> [pipeline: runs1] - cache.getBuildNumber(*_) >> 1 - mockService.getBuildServiceProvider() >> BuildServiceProvider.WERCKER - - when: - monitor.pollSingle(new PollContext(MASTER)) - - then: 'initial poll' - 0 * echoService.postEvent(_) - } - - void 'initial poll with completed runs'() { - given: - BuildServices buildServices = mockBuildServices() - - long now = System.currentTimeMillis(); - List runs1 = [ - new Run(id:"b", startedAt: new Date(now-10)), - new Run(id:"a", startedAt: new Date(now-11), finishedAt: new Date(now-11)), - new Run(id:"init", startedAt: new Date(now-12), finishedAt: new Date(now-10)), - ] - monitor = monitor(buildServices) - mockService.getRunsSince(_) >> [pipeline: runs1] - cache.getBuildNumber(*_) >> 1 - mockService.getBuildServiceProvider() >> BuildServiceProvider.WERCKER - - when: - monitor.pollSingle(new PollContext(MASTER)) - - then: 'initial poll' - 1 * echoService.postEvent(_) - } - - void 'select latest one from multiple completed runs'() { - given: - BuildServices buildServices = mockBuildServices() - monitor = monitor(buildServices) - cache.getBuildNumber(*_) >> 1 - mockService.getBuildServiceProvider() >> BuildServiceProvider.WERCKER - - when: - monitor.pollSingle(new PollContext(MASTER)) - - then: 'initial poll' - 0 * echoService.postEvent(_) - 1 * mockService.getRunsSince(_) >> [:] - - when: 'next poll' - long now = System.currentTimeMillis(); - List runs1 = [ - new Run(id:"b", startedAt: new Date(now-10)), - new Run(id:"a", startedAt: new Date(now-11), finishedAt: new Date(now-9)), - new Run(id:"init", startedAt: new Date(now-12), finishedAt: new Date(now-8)), - ] - cache.getLastPollCycleTimestamp(_, _) >> (now - 1000) - 1 * mockService.getRunsSince(_) >> [pipeline: runs1] - cache.getBuildNumber(*_) >> 1 - monitor.pollSingle(new PollContext(MASTER)) - - then: - 1 * cache.setEventPosted('MASTER', 'pipeline', 'init') - 1 * echoService.postEvent(_) - } - - void 'get runs of multiple pipelines'() { - setup: - BuildServices buildServices = new BuildServices() - buildServices.addServices([MASTER: werckerService]) - monitor = monitor(buildServices) - cache.getBuildNumber(*_) >> 1 - client.getRunsSince(_, _, _, _, _) >> [] - mockService.getBuildServiceProvider() >> BuildServiceProvider.WERCKER - - when: - monitor.pollSingle(new PollContext(MASTER)) - - then: 'initial poll' - 0 * echoService.postEvent(_) - - when: - monitor.pollSingle(new PollContext(MASTER)) - - then: - 0 * echoService.postEvent(_) - - when: 'next poll' - long now = System.currentTimeMillis(); - def org = 'myOrg' - def apps = [ - appOf('app0', org, [pipeOf('p00', 'pipeline')]), - appOf('app1', org, [ - pipeOf('p10', 'git'), - pipeOf('p11', 'git') - ]), - appOf('app2', org, [pipeOf('p20', 'git')]), - appOf('app3', org, [pipeOf('p30', 'git')]) - ] - List runs1 = [ - runOf('run0', now-10, now-1, apps[0], apps[0].pipelines[0]), - runOf('run1', now-10, now-1, apps[1], apps[1].pipelines[0]), - runOf('run2', now-10, now-2, apps[2], apps[2].pipelines[0]), - runOf('run3', now-10, now-1, apps[1], apps[1].pipelines[1]), - runOf('run4', now-10, now-1, apps[2], apps[2].pipelines[0]), - runOf('run5', now-10, null, apps[3], apps[3].pipelines[0]), - runOf('run6', now-10, now-2, apps[0], apps[0].pipelines[0]), - runOf('run6', now-10, now-3, apps[0], apps[0].pipelines[0]), - ] - client.getRunsSince(_,_,_,_,_) >> runs1 - cache.getLastPollCycleTimestamp(_, _) >> (now - 1000) - cache.getBuildNumber(*_) >> 1 - monitor.pollSingle(new PollContext(MASTER)) - - then: - 1 * cache.setEventPosted('MASTER', 'myOrg/app0/p00', 'run0') - 1 * cache.setEventPosted('MASTER', 'myOrg/app1/p10', 'run1') - 1 * cache.setEventPosted('MASTER', 'myOrg/app1/p11', 'run3') - 1 * cache.setEventPosted('MASTER', 'myOrg/app2/p20', 'run4') - 0 * cache.setEventPosted('MASTER', 'myOrg/app3/p30', 'run5') - 4 * echoService.postEvent(_) - } - - WerckerBuildMonitor monitor(BuildServices buildServices) { - def cfg = new IgorConfigurationProperties() - cfg.spinnaker.build.pollInterval = 1 - return new WerckerBuildMonitor( - cfg, - new NoopRegistry(), - new DynamicConfigService.NoopDynamicConfig(), - new DiscoveryStatusListener(true), - Optional.empty(), - cache, - buildServices, - true, - Optional.of(echoService), - new WerckerProperties(), - Mock(TaskScheduler) - ) - } - - Application appOf(String name, String owner, List pipelines) { - return new Application(name: name, owner: new Owner(name: owner), pipelines: pipelines) - } - - Pipeline pipeOf(String name, String type, String id=name) { - return new Pipeline(id: id, name: name, type: type) - } - - Run runOf(String id, long startedAt, Long finishedAt, Application app, Pipeline pipe) { - return new Run(id: id, startedAt: new Date(startedAt), finishedAt: finishedAt? new Date(finishedAt) : null, application: app, pipeline: pipe) - } -} diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerCacheSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerCacheSpec.groovy deleted file mode 100644 index 264165a1f..000000000 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerCacheSpec.groovy +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.igor.IgorConfigurationProperties -import com.netflix.spinnaker.igor.wercker.model.Run; -import com.netflix.spinnaker.kork.jedis.EmbeddedRedis -import com.netflix.spinnaker.kork.jedis.JedisClientDelegate -import com.netflix.spinnaker.kork.jedis.RedisClientDelegate - -import redis.clients.jedis.JedisPool -import spock.lang.Specification -import spock.lang.Subject - -class WerckerCacheSpec extends Specification { - - EmbeddedRedis embeddedRedis = EmbeddedRedis.embed() - RedisClientDelegate redisClientDelegate = new JedisClientDelegate(embeddedRedis.pool as JedisPool) - - @Subject - WerckerCache cache = new WerckerCache(redisClientDelegate, new IgorConfigurationProperties()) - - def master = 'testWerckerMaster' - def test = 'test' - def pipeline = 'myOrg/myApp/myTestPipeline' - - void cleanup() { - embeddedRedis.pool.resource.withCloseable { it.flushDB() } - embeddedRedis.destroy() - } - - void 'lastPollCycleTimestamp get overridden'() { - long now1 = System.currentTimeMillis(); - when: - cache.setLastPollCycleTimestamp(master, 'myOrg/myApp/myPipeline', now1) - then: - cache.getLastPollCycleTimestamp(master, 'myOrg/myApp/myPipeline') == now1 - - long now2 = System.currentTimeMillis(); - when: - cache.setLastPollCycleTimestamp(master, 'myOrg/myApp/myPipeline', now2) - then: - cache.getLastPollCycleTimestamp(master, 'myOrg/myApp/myPipeline') == now2 - } - - void 'generates buildNumbers ordered by startedAt'() { - long now = System.currentTimeMillis(); - List runs1 = [ - new Run(id:"b", startedAt: new Date(now-10)), - new Run(id:"a", createdAt: new Date(now-11)), - new Run(id:"init"), - ] - cache.updateBuildNumbers(master, pipeline, runs1) - - List runs2 = [ - new Run(id:"now", startedAt: new Date(now)), - new Run(id:"d", createdAt: new Date(now-1)), - new Run(id:"c", startedAt: new Date(now-2)), - ] - cache.updateBuildNumbers(master, pipeline, runs2) - - expect: - cache.getBuildNumber(master, pipeline, runId) == buildNumber - - where: - runId | buildNumber - 'init' | 0 - 'a' | 1 - 'b' | 2 - 'c' | 3 - 'd' | 4 - 'now' | 5 - } - - void 'generates buildNumbers ordered by createdAt'() { - long now = System.currentTimeMillis(); - List runs1 = [ - new Run(id:"y", createdAt: new Date(now-10)), - new Run(id:"x", startedAt: new Date(now-11)), - new Run(id:"zero", createdAt: new Date(now-12)), - ] - cache.updateBuildNumbers(master, pipeline, runs1) - - List runs2 = [ - new Run(id:"latest", createdAt: new Date(now)), - new Run(id:"4", startedAt: new Date(now-1)), - new Run(id:"3", createdAt: new Date(now-2)), - ] - cache.updateBuildNumbers(master, pipeline, runs2) - - expect: - cache.getBuildNumber(master, pipeline, runId) == buildNumber - - where: - runId | buildNumber - 'zero' | 0 - 'x' | 1 - 'y' | 2 - '3' | 3 - '4' | 4 - 'latest' | 5 - } -} diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerClientSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerClientSpec.groovy deleted file mode 100644 index a4c79c8ed..000000000 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerClientSpec.groovy +++ /dev/null @@ -1,110 +0,0 @@ - -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.config.okhttp3.InsecureOkHttpClientBuilderProvider -import com.netflix.spinnaker.config.okhttp3.OkHttpClientProvider -import com.netflix.spinnaker.igor.config.* -import com.netflix.spinnaker.igor.config.WerckerProperties.WerckerHost -import com.netflix.spinnaker.igor.wercker.model.* -import com.squareup.okhttp.mockwebserver.MockResponse -import com.squareup.okhttp.mockwebserver.MockWebServer -import okhttp3.OkHttpClient -import retrofit.RestAdapter -import spock.lang.Shared -import spock.lang.Specification - -class WerckerClientSpec extends Specification { - - @Shared - WerckerClient client - - @Shared - MockWebServer server - - void setup() { - server = new MockWebServer() - } - - void cleanup() { - server.shutdown() - } - - void 'get all applications'() { - setup: - def authHeader = "my_authHeader" - def limit = 300 - setResponse 'getApplications.js' - - when: - List apps = client.getApplications(authHeader, limit) - - then: - def request = server.takeRequest() - - expect: - apps.size() == 5 - request.path.startsWith('/api/spinnaker/v1/applications?') - request.path.contains('limit=' + limit) - assertApp(apps[0]) - assertApp(apps[2]) - } - - void 'get all runs since time'() { - given: - def authHeader = "my_authHeader" - def time = System.currentTimeMillis() - def branch = 'master' - def limit = 300 - setResponse 'getRuns.js' - - when: - List runs = client.getRunsSince(authHeader, branch, ['x', 'y', 'z'], limit, time) - - then: - def request = server.takeRequest() - - expect: - request.path.startsWith('/api/spinnaker/v1/runs?') - request.path.contains('branch=' + branch) - request.path.contains( 'limit=' + limit) - request.path.contains( 'since=' + time) - request.path.contains( 'pipelineIds=x') - request.path.contains( 'pipelineIds=y') - request.path.contains( 'pipelineIds=z') - runs.size() == 5 - assertRun(runs[1]) - assertRun(runs[4]) - } - - def assertApp(Application app) { - app.id && app.name && app.owner && app.pipelines - } - - def assertRun(Run run) { - run.id && run.status && run.user && - run.application && run.pipeline - } - - private void setResponse(String fileName) { - server.enqueue( - new MockResponse() - .setBody(read(fileName)) - .setHeader('Content-Type', 'application/json; charset=utf-8') - ) - server.start() - def host = new WerckerHost(name: 'werckerMaster', address: server.url('/').toString()) - client = new WerckerConfig().werckerClient(host, 30000, new OkHttpClientProvider([new InsecureOkHttpClientBuilderProvider(new OkHttpClient())]), RestAdapter.LogLevel.BASIC) - } - - String read(String fileName) { - return new File(getClass().getResource('/wercker/' + fileName).toURI()).text - } -} diff --git a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerServiceSpec.groovy b/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerServiceSpec.groovy deleted file mode 100644 index f1f6e0cd1..000000000 --- a/igor-web/src/test/groovy/com/netflix/spinnaker/igor/wercker/WerckerServiceSpec.groovy +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle Corporation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the Apache License Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * If a copy of the Apache License Version 2.0 was not distributed with this file, - * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html - */ - -package com.netflix.spinnaker.igor.wercker - -import com.netflix.spinnaker.fiat.model.resources.Permissions -import com.netflix.spinnaker.igor.config.WerckerProperties.WerckerHost -import com.netflix.spinnaker.igor.wercker.model.* - -import spock.lang.Shared -import spock.lang.Specification - -class WerckerServiceSpec extends Specification { - - WerckerCache cache = Mock(WerckerCache) - - @Shared - WerckerClient client - - @Shared - WerckerService service - String werckerDev = 'https://dev.wercker.com/' - String master = 'WerckerTestMaster' - - void setup() { - client = Mock(WerckerClient) - service = new WerckerService( - new WerckerHost(name: master, address: werckerDev), cache, client, Permissions.EMPTY) - } - - void 'get pipelines as jobs'() { - setup: - client.getApplications(_,_) >> [ - appOf('myApp1', 'coo', [pipeOf('myPipeA', 'newType')]), - appOf('myApp2', 'foo', [ - pipeOf('myPipeX', 'x'), - pipeOf('myPipeY', 'y') - ]) - ] - - expect: - service.jobs.size == 3 - service.jobs.contains('x/foo/myApp2/myPipeX') - } - - void 'get pipelineId and builds'() { - setup: - def names = ['myOrg', 'myApp', 'myPipe'] - def (org, app, pipe) = names - def pipeline = names.join('/') - def pipelineId = pipe + "ID" - List pipelines = [ - pipeOf('anotherPipe', 'git'), - pipeOf(pipe, 'git', pipelineId) - ] - def now = System.currentTimeMillis() - List runs = [ - runOf('1', now-1, appOf(app, org, []), pipelines[1]), - runOf('2', now-2, appOf(app, org, []), pipelines[1]), - runOf('3', now-3, appOf(app, org, []), pipelines[1]) - ] - client.getPipelinesForApplication(_, org, app) >> pipelines - client.getRunsForPipeline(_, pipelineId) >> runs - - expect: - service.getBuilds(pipeline) == runs - } - - void 'get builds with pipelineId'() { - setup: - def (org, app, pipe) = ["myOrg", "myApp", "myPipe"] - def (pipelineId, pipeline) = [ - 'myPipelineID', - org + '/' + app + '/' + pipe - ] - def now = System.currentTimeMillis() - List runs = [ - runOf('1', now-1, null, null), - runOf('2', now-2, appOf(app, org, []), pipeOf(pipe, 'git')), - runOf('3', now-3, appOf(app, org, []), pipeOf(pipe, 'git')) - ] - cache.getPipelineID(_, pipeline) >> pipelineId - client.getRunsForPipeline(_, pipelineId) >> runs - - expect: - service.getBuilds(pipeline) == runs - } - - void 'categorize runs with pipelineQName'() { - setup: - long now = System.currentTimeMillis() - long since = now-1000 - def app1 = appOf('app1', 'org1', []) - def app2 = appOf('app2', 'org1', []) - def pipe1 = pipeOf('p1', 'git', 'a', app1) - def pipe2 = pipeOf('p2', 'git', 'b', app2) - def pipe3 = pipeOf('p3', 'git', 'c', app1) - List runs1 = [ - runOf('1', now-10, app1, pipe1, 'a'), - runOf('2', now-10, app2, pipe2, 'b'), - runOf('3', now-10, app1, pipe3, 'c'), - runOf('4', now-10, app2, pipe2, 'b'), - ] - client.getRunsSince(_,_,_,_,since) >> runs1 - client.getPipeline(_, 'a') >> pipe1 - client.getPipeline(_, 'b') >> pipe2 - client.getPipeline(_, 'c') >> pipe3 - - expect: - service.getRunsSince(since).size() == 3 - service.getRunsSince(since).get('org1/app2/p2').size() == 2 - service.getRunsSince(since).get('org1/app1/p1').size() == 1 - service.getRunsSince(since).get('org1/app1/p3').size() == 1 - } - - void 'get GenericBuild with buildNumber'() { - def names = [ - 'testOrg', - 'testApp', - 'testPipe' - ] - def (org, app, pipe) = names - def job = names.join('/') - def runId = "testGenericBuild_werckerRunId" - int buildNumber = 6 - setup: - cache.getRunID(master, job, buildNumber) >> runId - client.getRunById(_, runId) >> new Run(id: runId) - - expect: - service.getGenericBuild(job, buildNumber).url == werckerDev + org + '/' + app + '/runs/' + pipe + '/' + runId - service.getGenericBuild(job, buildNumber).building == true - } - - void 'test triggerBuildWithParameters'() { - def names = [ - 'testOrg', - 'testApp', - 'testPipe' - ] - def (org, app, pipe) = names - def (pipeline, pipelineId) = [names.join('/'), pipe + "ID"] - def runId = 'test_triggerBuild_runId' - int buildNumber = 8 - - setup: - client.getPipelinesForApplication(_, org, app) >> [ - pipeOf('foo', 'git'), - pipeOf(pipe, 'git', pipelineId) - ] - client.triggerBuild(_, _) >> ['id': runId] - client.getRunById(_, runId) >> new Run(id: runId) - cache.updateBuildNumbers(master, pipeline, _) >> ['test_triggerBuild_runId': buildNumber] - - expect: - service.triggerBuildWithParameters(pipeline, [:]) == buildNumber - } - - Application appOf(String name, String owner, List pipelines) { - return new Application(name: name, owner: new Owner(name: owner), pipelines: pipelines) - } - - Pipeline pipeOf(String name, String type, String id=name) { - return new Pipeline(id: id, name: name, type: type) - } - - Pipeline pipeOf(String name, String type, String id=name, Application app) { - return new Pipeline(id: id, name: name, type: type, application: app) - } - - Run runOf(String id, long startedAt, Application app, Pipeline pipe, String pid=null) { - return new Run(id: id, startedAt: new Date(startedAt), application: app, pipeline: pipe, pipelineId: pid) - } -} diff --git a/igor-web/src/test/resources/wercker/getApplications.js b/igor-web/src/test/resources/wercker/getApplications.js deleted file mode 100644 index 8b3edaa46..000000000 --- a/igor-web/src/test/resources/wercker/getApplications.js +++ /dev/null @@ -1,247 +0,0 @@ -[ - { - "id": "58344deddd22a50100526763", - "url": "http://localhost:3000/api/v3/applications/wercker/ark", - "name": "ark", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - }, - "createdAt": "2016-11-22T13:53:49.807Z", - "updatedAt": "2016-12-01T15:22:21.865Z", - "privacy": "private", - "stack": 6, - "theme": "Amethyst", - "pipelines": [ - { - "id": "58344deed35d1401003f18c7", - "url": "http://localhost:3000/api/v3/pipelines/58344deed35d1401003f18c7", - "createdAt": "2016-11-22T13:53:50.383Z", - "name": "build", - "permissions": "public", - "pipelineName": "build", - "setScmProviderStatus": true, - "type": "git" - }, - { - "id": "583471d9dd22a501005268e5", - "url": "http://localhost:3000/api/v3/pipelines/583471d9dd22a501005268e5", - "createdAt": "2016-11-22T16:27:05.816Z", - "name": "push-quay", - "permissions": "read", - "pipelineName": "push-quay", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "58347282dd22a501005268e7", - "url": "http://localhost:3000/api/v3/pipelines/58347282dd22a501005268e7", - "createdAt": "2016-11-22T16:29:54.792Z", - "name": "deploy-kube-staging", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "585d3f6f84027801002a59f5", - "url": "http://localhost:3000/api/v3/pipelines/585d3f6f84027801002a59f5", - "createdAt": "2016-12-23T15:14:55.599Z", - "name": "deploy-kube-production", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - } - ] - }, - { - "id": "57bda6e9e382a101002ce7c1", - "url": "http://localhost:3000/api/v3/applications/wercker/auth", - "name": "auth", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - }, - "createdAt": "2016-08-24T13:53:45.870Z", - "updatedAt": "2016-08-24T13:53:45.869Z", - "privacy": "private", - "stack": 6, - "theme": "Cosmopolitan", - "pipelines": [ - { - "id": "57bda6ea8404640100e7004f", - "url": "http://localhost:3000/api/v3/pipelines/57bda6ea8404640100e7004f", - "createdAt": "2016-08-24T13:53:46.253Z", - "name": "build", - "permissions": "public", - "pipelineName": "build", - "setScmProviderStatus": true, - "type": "git" - }, - { - "id": "57bdbff48404640100e700e1", - "url": "http://localhost:3000/api/v3/pipelines/57bdbff48404640100e700e1", - "createdAt": "2016-08-24T15:40:36.402Z", - "name": "push-quay", - "permissions": "read", - "pipelineName": "push-quay", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "57bdbff48404640100e700e3", - "url": "http://localhost:3000/api/v3/pipelines/57bdbff48404640100e700e3", - "createdAt": "2016-08-24T15:40:36.694Z", - "name": "deploy-kube-staging", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "585d3532180d780100492891", - "url": "http://localhost:3000/api/v3/pipelines/585d3532180d780100492891", - "createdAt": "2016-12-23T14:31:14.953Z", - "name": "deploy-kube-production", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - } - ] - }, - { - "id": "57fe0a5ce644cd01001e1de3", - "url": "http://localhost:3000/api/v3/applications/wercker/bcarter", - "name": "bcarter", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - }, - "createdAt": "2016-10-12T10:03:08.278Z", - "updatedAt": "2016-10-12T10:03:08.278Z", - "privacy": "private", - "stack": 6, - "theme": "Appletini", - "pipelines": [ - { - "id": "57fe0a5c56f1d70100076cc5", - "url": "http://localhost:3000/api/v3/pipelines/57fe0a5c56f1d70100076cc5", - "createdAt": "2016-10-12T10:03:08.729Z", - "name": "build", - "permissions": "public", - "pipelineName": "build", - "setScmProviderStatus": true, - "type": "git" - } - ] - }, - { - "id": "588f5baf5e93a901000fe15c", - "url": "http://localhost:3000/api/v3/applications/wercker/bitbucket-hook", - "name": "bitbucket-hook", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - }, - "createdAt": "2017-01-30T15:28:47.276Z", - "updatedAt": "2018-04-05T08:32:41.155Z", - "privacy": "private", - "stack": 6, - "theme": "Onyx", - "pipelines": [ - { - "id": "588f5baf5e93a901000fe15f", - "url": "http://localhost:3000/api/v3/pipelines/588f5baf5e93a901000fe15f", - "createdAt": "2017-01-30T15:28:47.588Z", - "name": "build", - "permissions": "public", - "pipelineName": "build", - "setScmProviderStatus": true, - "type": "git" - } - ] - }, - { - "id": "5989b9136f0ad8010098862c", - "url": "http://localhost:3000/api/v3/applications/wercker/blackbox", - "name": "blackbox", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - }, - "createdAt": "2017-08-08T13:13:55.471Z", - "updatedAt": "2017-08-08T13:13:55.471Z", - "privacy": "private", - "stack": 6, - "theme": "Amethyst", - "pipelines": [ - { - "id": "5989b9133b59d401009f2900", - "url": "http://localhost:3000/api/v3/pipelines/5989b9133b59d401009f2900", - "createdAt": "2017-08-08T13:13:55.951Z", - "name": "build", - "permissions": "public", - "pipelineName": "build", - "setScmProviderStatus": true, - "type": "git" - }, - { - "id": "5989bfb83b59d401009f294e", - "url": "http://localhost:3000/api/v3/pipelines/5989bfb83b59d401009f294e", - "createdAt": "2017-08-08T13:42:16.047Z", - "name": "push-quay", - "permissions": "read", - "pipelineName": "push-quay", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "5989cda13b59d401009f2ad4", - "url": "http://localhost:3000/api/v3/pipelines/5989cda13b59d401009f2ad4", - "createdAt": "2017-08-08T14:41:37.025Z", - "name": "deploy-kube-staging", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - }, - { - "id": "5989ce5b3b59d401009f2ad6", - "url": "http://localhost:3000/api/v3/pipelines/5989ce5b3b59d401009f2ad6", - "createdAt": "2017-08-08T14:44:43.146Z", - "name": "deploy-kube-production", - "permissions": "read", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - } - ] - } -] \ No newline at end of file diff --git a/igor-web/src/test/resources/wercker/getRuns.js b/igor-web/src/test/resources/wercker/getRuns.js deleted file mode 100644 index f22829697..000000000 --- a/igor-web/src/test/resources/wercker/getRuns.js +++ /dev/null @@ -1,232 +0,0 @@ -[ - { - "id": "5b1aad44d9ee220001d2bd49", - "url": "http://localhost:3000/api/v3/runs/5b1aad44d9ee220001d2bd49", - "branch": "master", - "commitHash": "03e865018aec134df6375e1dc3d685df7d525ed5", - "createdAt": "2018-06-08T16:22:28.310Z", - "finishedAt": "2018-06-08T16:22:51.349Z", - "message": "WRKR-508: add http(s) git url syntax support like ssh (#416)\n\n* add http(s) git url syntax support like ssh\r\n\r\n* add tests for ssh and http(s)", - "progress": null, - "result": "passed", - "startedAt": "2018-06-08T16:22:28.458Z", - "status": "finished", - "user": { - "type": "wercker", - "name": "Dave", - "avatar": { - "gravatar": "37de3d3a5f3cf88e113d83ac134a6216" - }, - "meta": { - "username": "ddiamond", - "type": "user" - }, - "userId": "5a69f67111d939010054a694" - }, - "pipeline": { - "id": "59039d8c9881700100cf38f7", - "url": "http://localhost:3000/api/v3/pipelines/59039d8c9881700100cf38f7", - "name": "deploy-vpp-pool-staging", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - }, - "application": { - "id": "57bda698e382a101002ce795", - "name": "kiddie-pool", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - } - } - }, - { - "id": "5b1aa408c16dd30001298629", - "url": "http://localhost:3000/api/v3/runs/5b1aa408c16dd30001298629", - "branch": "master", - "commitHash": "03e865018aec134df6375e1dc3d685df7d525ed5", - "createdAt": "2018-06-08T15:43:04.334Z", - "finishedAt": "2018-06-08T15:46:27.170Z", - "message": "WRKR-508: add http(s) git url syntax support like ssh (#416)\n\n* add http(s) git url syntax support like ssh\r\n\r\n* add tests for ssh and http(s)", - "progress": null, - "result": "passed", - "startedAt": "2018-06-08T15:43:05.305Z", - "status": "finished", - "user": { - "type": "wercker", - "name": "Dave", - "avatar": { - "gravatar": "37de3d3a5f3cf88e113d83ac134a6216" - }, - "meta": { - "username": "ddiamond", - "type": "" - }, - "userId": "5a69f67111d939010054a694" - }, - "pipeline": { - "id": "57bda6988404640100e70033", - "url": "http://localhost:3000/api/v3/pipelines/57bda6988404640100e70033", - "name": "build", - "pipelineName": "build", - "setScmProviderStatus": false, - "type": "git" - }, - "application": { - "id": "57bda698e382a101002ce795", - "name": "kiddie-pool", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - } - } - }, - { - "id": "5b1a96e5d9ee220001d2bd1f", - "url": "http://localhost:3000/api/v3/runs/5b1a96e5d9ee220001d2bd1f", - "branch": "master", - "commitHash": "8cfcc8436ded45e060e196c9ca189ca07e9dd63a", - "createdAt": "2018-06-08T14:47:01.511Z", - "finishedAt": "2018-06-08T14:48:17.124Z", - "message": "Merge pull request #37 from wercker/get-runners-api2\n\nInitial implementation of list runners REST API and 11 more commits", - "progress": null, - "result": "passed", - "startedAt": "2018-06-08T14:47:55.074Z", - "status": "finished", - "user": { - "type": "wercker", - "name": "mgianatawkr", - "avatar": { - "gravatar": "e349d20d3a9af547164b6ad11eed084c" - }, - "meta": { - "username": "mgianatawkr", - "type": "user" - }, - "userId": "5a6b9b4c398c4d0100b3ce1b" - }, - "pipeline": { - "id": "5a02efb6a538b80100a9697f", - "url": "http://localhost:3000/api/v3/pipelines/5a02efb6a538b80100a9697f", - "name": "deploy-kube-staging", - "pipelineName": "deploy-kube", - "setScmProviderStatus": false, - "type": "pipeline" - }, - "application": { - "id": "5a02ee3d70957b0100f40d9c", - "name": "dispatch", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - } - } - }, - { - "id": "5b1a9558c16dd3000129854e", - "url": "http://localhost:3000/api/v3/runs/5b1a9558c16dd3000129854e", - "branch": "master", - "commitHash": "8cfcc8436ded45e060e196c9ca189ca07e9dd63a", - "createdAt": "2018-06-08T14:40:24.238Z", - "finishedAt": "2018-06-08T14:41:58.578Z", - "message": "Merge pull request #37 from wercker/get-runners-api2\n\nInitial implementation of list runners REST API", - "progress": null, - "result": "passed", - "startedAt": "2018-06-08T14:40:24.295Z", - "status": "finished", - "user": { - "type": "wercker", - "name": "mgianatawkr", - "avatar": { - "gravatar": "e349d20d3a9af547164b6ad11eed084c" - }, - "meta": { - "username": "mgianatawkr", - "type": "" - }, - "userId": "5a6b9b4c398c4d0100b3ce1b" - }, - "pipeline": { - "id": "5a02ee3ea538b80100a9697a", - "url": "http://localhost:3000/api/v3/pipelines/5a02ee3ea538b80100a9697a", - "name": "build", - "pipelineName": "build", - "setScmProviderStatus": false, - "type": "git" - }, - "application": { - "id": "5a02ee3d70957b0100f40d9c", - "name": "dispatch", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - } - } - }, - { - "id": "5b1a85786c06e50001c3794e", - "url": "http://localhost:3000/api/v3/runs/5b1a85786c06e50001c3794e", - "branch": "master", - "commitHash": "6d8143aa9db81e4ed07194406e7a9eda8c6816ee", - "createdAt": "2018-06-08T13:32:40.347Z", - "finishedAt": "2018-06-08T13:36:03.552Z", - "message": "Remove checked in vendor code (#415)", - "progress": null, - "result": "passed", - "startedAt": "2018-06-08T13:32:40.437Z", - "status": "finished", - "user": { - "type": "wercker", - "name": "bihaber", - "avatar": { - "gravatar": "d06fa182c64008c9c88a2b0bb513e635" - }, - "meta": { - "username": "bihaber", - "type": "" - }, - "userId": "5a69ee7270a6330100ab65e1" - }, - "pipeline": { - "id": "57bda6988404640100e70033", - "url": "http://localhost:3000/api/v3/pipelines/57bda6988404640100e70033", - "name": "build", - "pipelineName": "build", - "setScmProviderStatus": false, - "type": "git" - }, - "application": { - "id": "57bda698e382a101002ce795", - "name": "kiddie-pool", - "owner": { - "userId": "5530d21f3151d2c55400006f", - "name": "wercker", - "meta": { - "username": "wercker", - "type": "organization", - "werckerEmployee": false - } - } - } - } -] \ No newline at end of file