• 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

9.86
/plugins/pipelines/sync.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 idSchema = schema.models.pipeline.base.extract('id');
1✔
7
const logger = require('screwdriver-logger');
1✔
8
const { getScmUri } = require('../helper');
1✔
9

10
module.exports = () => ({
434✔
11
    method: 'POST',
12
    path: '/pipelines/{id}/sync',
13
    options: {
14
        description: 'Sync a pipeline',
15
        notes: 'Sync a specific pipeline',
16
        tags: ['api', 'pipelines'],
17
        auth: {
18
            strategies: ['token'],
19
            scope: ['user', '!guest', 'pipeline']
20
        },
21

22
        handler: async (request, h) => {
UNCOV
23
            const { id } = request.params;
×
UNCOV
24
            const { pipelineFactory, userFactory } = request.server.app;
×
UNCOV
25
            const { username, scmContext, scope } = request.auth.credentials;
×
UNCOV
26
            const { isValidToken } = request.server.plugins.pipelines;
×
27

UNCOV
28
            if (!isValidToken(id, request.auth.credentials)) {
×
UNCOV
29
                return boom.unauthorized('Token does not have permission to this pipeline');
×
30
            }
31

32
            // Fetch the pipeline and user models
UNCOV
33
            const [pipeline, user] = await Promise.all([
×
34
                pipelineFactory.get(id),
35
                userFactory.get({ username, scmContext })
36
            ]);
37

UNCOV
38
            if (!pipeline) {
×
UNCOV
39
                throw boom.notFound('Pipeline does not exist');
×
40
            }
UNCOV
41
            if (pipeline.state === 'DELETING') {
×
UNCOV
42
                throw boom.conflict('This pipeline is being deleted.');
×
43
            }
UNCOV
44
            if (!user) {
×
UNCOV
45
                throw boom.notFound(`User ${username} does not exist`);
×
46
            }
47
            // for mysql backward compatibility
UNCOV
48
            if (!pipeline.adminUserIds) {
×
49
                pipeline.adminUserIds = [];
×
50
            }
51

52
            // Use parent's scmUri if pipeline is child pipeline and using read-only SCM
UNCOV
53
            const scmUri = await getScmUri({ pipeline, pipelineFactory });
×
UNCOV
54
            let hasPushPermissions = false;
×
55
            let permissions;
56

UNCOV
57
            try {
×
58
                // Get user permissions
UNCOV
59
                permissions = await user.getPermissions(scmUri);
×
60
            } catch (error) {
UNCOV
61
                throw boom.boomify(error, { statusCode: error.statusCode });
×
62
            }
63

64
            // check if user has push access
UNCOV
65
            if (!permissions.push) {
×
66
                // user is not permitted, delete from admins table
UNCOV
67
                const newAdmins = pipeline.admins;
×
68

UNCOV
69
                delete newAdmins[username];
×
UNCOV
70
                const newAdminUserIds = pipeline.adminUserIds.filter(adminUserId => adminUserId !== user.id);
×
71

72
                // This is needed to make admins dirty and update db
UNCOV
73
                pipeline.admins = newAdmins;
×
UNCOV
74
                pipeline.adminUserIds = newAdminUserIds;
×
75

UNCOV
76
                await pipeline.update();
×
77

UNCOV
78
                if (!scope.includes('admin')) {
×
UNCOV
79
                    throw boom.forbidden(
×
80
                        `User ${user.getFullDisplayName()} does not have push permission for this repo`
81
                    );
82
                }
83
            } else {
UNCOV
84
                hasPushPermissions = true;
×
85
            }
86

87
            // user has good permissions, add the user as an admin
UNCOV
88
            if (!pipeline.admins[username] && hasPushPermissions) {
×
UNCOV
89
                const newAdmins = pipeline.admins;
×
UNCOV
90
                const newAdminUserIds = pipeline.adminUserIds;
×
91

UNCOV
92
                newAdmins[username] = true;
×
UNCOV
93
                if (!newAdminUserIds.includes(user.id)) {
×
UNCOV
94
                    newAdminUserIds.push(user.id);
×
95
                }
96

97
                // This is needed to make admins dirty and update db
UNCOV
98
                pipeline.admins = newAdmins;
×
UNCOV
99
                pipeline.adminUserIds = newAdminUserIds;
×
100

UNCOV
101
                await pipeline.update();
×
102
            }
103

UNCOV
104
            try {
×
UNCOV
105
                await pipeline.sync();
×
106

UNCOV
107
                return h.response().code(204);
×
108
            } catch (err) {
UNCOV
109
                logger.error(`Failed to sync pipeline:${pipeline.id}`, err);
×
UNCOV
110
                throw err;
×
111
            }
112
        },
113
        validate: {
114
            params: joi.object({
115
                id: idSchema
116
            })
117
        }
118
    }
119
});
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