• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

screwdriver-cd / screwdriver / #3202

25 Jul 2025 04:52PM UTC coverage: 67.669% (-27.3%) from 94.935%
#3202

push

screwdriver

web-flow
feat(3363): Update the existing endpoint to get admin for a pipeline from the specified SCM context (#3370)

1284 of 2114 branches covered (60.74%)

Branch coverage included in aggregate %.

1 of 11 new or added lines in 1 file covered. (9.09%)

1235 existing lines in 49 files now uncovered.

3417 of 4833 relevant lines covered (70.7%)

50.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

10.17
/plugins/pipelines/updateBuildCluster.js
1
'use strict';
2

3
const boom = require('@hapi/boom');
1✔
4
const joi = require('joi');
1✔
5
const schema = require('screwdriver-data-schema');
1✔
6
const logger = require('screwdriver-logger');
1✔
7
const idSchema = schema.models.pipeline.base.extract('id');
1✔
8

9
module.exports = () => ({
434✔
10
    method: 'PUT',
11
    path: '/pipelines/{id}/buildCluster',
12
    options: {
13
        description: 'Update the buildCluster of a pipeline',
14
        notes: 'Update the buildCluster of a specific pipeline',
15
        tags: ['api', 'pipelines'],
16
        auth: {
17
            strategies: ['token'],
18
            scope: ['user', '!guest']
19
        },
20
        handler: async (request, h) => {
UNCOV
21
            const buildClusterAnnotation = 'screwdriver.cd/buildCluster';
×
UNCOV
22
            const { payload } = request;
×
23

24
            // payload should have buildCluster annotation
UNCOV
25
            if (!payload[buildClusterAnnotation]) {
×
UNCOV
26
                throw boom.badRequest(`Payload must contain ${buildClusterAnnotation}`);
×
27
            }
28

UNCOV
29
            const { pipelineFactory, bannerFactory, buildClusterFactory } = request.server.app;
×
UNCOV
30
            const { scmContext, username, scmUserId } = request.auth.credentials;
×
31

32
            // only SD cluster admins can update the buildCluster
UNCOV
33
            const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
×
UNCOV
34
            const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
×
35
                username,
36
                scmDisplayName,
37
                scmUserId
38
            );
39

UNCOV
40
            if (!adminDetails.isAdmin) {
×
UNCOV
41
                throw boom.forbidden(
×
42
                    `User ${username} does not have Screwdriver administrative privileges to update the buildCluster`
43
                );
44
            }
45

UNCOV
46
            const { id } = request.params;
×
UNCOV
47
            const pipeline = await pipelineFactory.get({ id });
×
48

49
            // check if pipeline exists
UNCOV
50
            if (!pipeline) {
×
UNCOV
51
                throw boom.notFound(`Pipeline ${id} does not exist`);
×
52
            }
UNCOV
53
            if (pipeline.state === 'DELETING') {
×
UNCOV
54
                throw boom.conflict('This pipeline is being deleted.');
×
55
            }
56

UNCOV
57
            const pipelineConfig = await pipeline.getConfiguration({});
×
58
            // check if pipeline has buildCluster annotation
59

UNCOV
60
            if (pipelineConfig.annotations && pipelineConfig.annotations[buildClusterAnnotation]) {
×
61
                const scmUrl = pipeline.scmRepo.url;
×
62

63
                throw boom.conflict(
×
64
                    `Pipeline ${id} already has a buildCluster annotation set in the YAML configuration: check ${scmUrl}`
65
                );
66
            }
67

68
            // ensure that the buildCluster is a valid cluster
UNCOV
69
            const buildClusterName = payload[buildClusterAnnotation];
×
UNCOV
70
            const buildCluster = await buildClusterFactory.get({ name: buildClusterName, scmContext });
×
71

UNCOV
72
            if (!buildCluster) {
×
UNCOV
73
                throw boom.badRequest(`Build cluster ${buildClusterName} does not exist`);
×
74
            }
75

76
            // ensure that the buildCluster is active
UNCOV
77
            if (!buildCluster.isActive) {
×
UNCOV
78
                throw boom.badRequest(`Build cluster ${buildClusterName} is not active`);
×
79
            }
80

81
            // update pipeline with buildCluster annotation
UNCOV
82
            if (!pipeline.annotations) {
×
UNCOV
83
                pipeline.annotations = {};
×
84
            }
UNCOV
85
            pipeline.annotations[buildClusterAnnotation] = buildClusterName;
×
UNCOV
86
            try {
×
UNCOV
87
                const result = await pipeline.update();
×
88

UNCOV
89
                logger.info(
×
90
                    `[Audit] user ${username} updates ${buildClusterAnnotation} for pipelineID:${id} to ${buildClusterName}.`
91
                );
92

UNCOV
93
                return h.response(result.toJson()).code(200);
×
94
            } catch (err) {
UNCOV
95
                logger.error(`Failed to update ${buildClusterAnnotation} for pipeline ${id}: ${err.message}`);
×
UNCOV
96
                throw boom.internal(`Failed to update ${buildClusterAnnotation} for pipeline ${id}`);
×
97
            }
98
        },
99
        validate: {
100
            params: joi.object({
101
                id: idSchema
102
            })
103
        }
104
    }
105
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc