@salesforce/plugin-devops-center 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -100
- package/lib/commands/devops/pipeline/activate.js +5 -0
- package/lib/commands/devops/pipeline/activate.js.map +1 -1
- package/lib/commands/devops/pipeline/create.d.ts +2 -1
- package/lib/commands/devops/pipeline/create.js +37 -7
- package/lib/commands/devops/pipeline/create.js.map +1 -1
- package/lib/commands/devops/pipeline/{attach-project.d.ts → project/add.d.ts} +2 -2
- package/lib/commands/devops/pipeline/{attach-project.js → project/add.js} +5 -5
- package/lib/commands/devops/pipeline/project/add.js.map +1 -0
- package/lib/commands/devops/pull-request/create.d.ts +0 -2
- package/lib/commands/devops/pull-request/create.js +8 -40
- package/lib/commands/devops/pull-request/create.js.map +1 -1
- package/lib/commands/devops/stage/{add-branch.d.ts → branch/add.d.ts} +2 -2
- package/lib/commands/devops/stage/{add-branch.js → branch/add.js} +6 -6
- package/lib/commands/devops/stage/branch/add.js.map +1 -0
- package/lib/commands/devops/stage/{add-environment.d.ts → environment/add.d.ts} +2 -2
- package/lib/commands/devops/stage/{add-environment.js → environment/add.js} +11 -6
- package/lib/commands/devops/stage/environment/add.js.map +1 -0
- package/lib/commands/devops/work-item/{status/update.d.ts → update.d.ts} +6 -4
- package/lib/commands/devops/work-item/{status/update.js → update.js} +30 -9
- package/lib/commands/devops/work-item/update.js.map +1 -0
- package/lib/utils/createPipeline.d.ts +14 -1
- package/lib/utils/createPipeline.js +52 -6
- package/lib/utils/createPipeline.js.map +1 -1
- package/lib/utils/createProject.js +1 -0
- package/lib/utils/createProject.js.map +1 -1
- package/lib/utils/createPullRequest.d.ts +7 -19
- package/lib/utils/createPullRequest.js +49 -121
- package/lib/utils/createPullRequest.js.map +1 -1
- package/lib/utils/{updateWorkItemStatus.d.ts → updateWorkItem.d.ts} +12 -14
- package/lib/utils/{updateWorkItemStatus.js → updateWorkItem.js} +28 -26
- package/lib/utils/updateWorkItem.js.map +1 -0
- package/messages/devops.pipeline.create.md +26 -6
- package/messages/devops.pull-request.create.md +6 -30
- package/messages/{devops.stage.add-environment.md → devops.stage.environment.add.md} +4 -0
- package/messages/devops.work-item.update.md +45 -0
- package/npm-shrinkwrap.json +2 -2
- package/oclif.manifest.json +276 -266
- package/package.json +3 -3
- package/schemas/devops-pull__request-create.json +0 -3
- package/schemas/{devops-work__item-status-update.json → devops-work__item-update.json} +8 -2
- package/lib/commands/devops/pipeline/attach-project.js.map +0 -1
- package/lib/commands/devops/stage/add-branch.js.map +0 -1
- package/lib/commands/devops/stage/add-environment.js.map +0 -1
- package/lib/commands/devops/work-item/status/update.js.map +0 -1
- package/lib/utils/updateWorkItemStatus.js.map +0 -1
- package/messages/devops.work-item.status.update.md +0 -29
- /package/messages/{devops.pipeline.attach-project.md → devops.pipeline.project.add.md} +0 -0
- /package/messages/{devops.stage.add-branch.md → devops.stage.branch.add.md} +0 -0
- /package/schemas/{devops-pipeline-attach__project.json → devops-pipeline-project-add.json} +0 -0
- /package/schemas/{devops-stage-add__branch.json → devops-stage-branch-add.json} +0 -0
- /package/schemas/{devops-stage-add__environment.json → devops-stage-environment-add.json} +0 -0
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { execSync } from 'node:child_process';
|
|
16
17
|
import { getPipelineIdForProject, fetchPipelineStages, computeFirstStageId, findStageById, getBranchNameFromStage, resolveTargetStageId, } from './pipelineUtils.js';
|
|
17
18
|
function normalizeProvider(provider) {
|
|
18
19
|
if (!provider)
|
|
@@ -22,52 +23,14 @@ function normalizeProvider(provider) {
|
|
|
22
23
|
return 'bitbucket';
|
|
23
24
|
return normalized;
|
|
24
25
|
}
|
|
25
|
-
function providerToVcsType(provider) {
|
|
26
|
-
const normalized = normalizeProvider(provider);
|
|
27
|
-
if (normalized === 'github')
|
|
28
|
-
return 'GITHUB';
|
|
29
|
-
if (normalized === 'bitbucket')
|
|
30
|
-
return 'BITBUCKET';
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
function extractOwnerFromVcsPayload(payload) {
|
|
34
|
-
if (!payload)
|
|
35
|
-
return undefined;
|
|
36
|
-
if (typeof payload === 'string')
|
|
37
|
-
return payload.trim() || undefined;
|
|
38
|
-
const obj = payload;
|
|
39
|
-
if (typeof obj.owner === 'string' && obj.owner.trim())
|
|
40
|
-
return obj.owner.trim();
|
|
41
|
-
const list = (obj.owners ?? obj.items ?? obj.records);
|
|
42
|
-
if (Array.isArray(list)) {
|
|
43
|
-
for (const candidate of list) {
|
|
44
|
-
if (typeof candidate === 'string' && candidate.trim())
|
|
45
|
-
return candidate.trim();
|
|
46
|
-
if (candidate && typeof candidate === 'object') {
|
|
47
|
-
const ownerVal = candidate.owner;
|
|
48
|
-
if (typeof ownerVal === 'string' && ownerVal.trim())
|
|
49
|
-
return ownerVal.trim();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
async function fetchOwnerByVcsType(connection, vcsType) {
|
|
56
|
-
const path = `/services/data/v${connection.getApiVersion()}/connect/devops/vcs/${vcsType}`;
|
|
57
|
-
const response = await connection.request({ method: 'GET', url: path });
|
|
58
|
-
return extractOwnerFromVcsPayload(response);
|
|
59
|
-
}
|
|
60
26
|
/**
|
|
61
|
-
* Queries a work item (by Name or Id) and resolves
|
|
62
|
-
* to create a pull request: branch, repo, owner, provider, and target branch.
|
|
27
|
+
* Queries a work item (by Name or Id) and resolves info needed to create a pull request.
|
|
63
28
|
*/
|
|
64
29
|
export async function fetchWorkItemDetail(connection, filter) {
|
|
65
30
|
const whereClause = 'name' in filter ? `Name = '${filter.name}'` : `Id = '${filter.id}'`;
|
|
66
31
|
const identifier = 'name' in filter ? filter.name : filter.id;
|
|
67
32
|
const result = await connection.query(`SELECT Id, Name, Subject, DevopsProjectId, DevopsPipelineStageId,
|
|
68
33
|
SourceCodeRepositoryBranch.Name,
|
|
69
|
-
SourceCodeRepositoryBranch.SourceCodeRepository.Name,
|
|
70
|
-
SourceCodeRepositoryBranch.SourceCodeRepository.RepositoryOwner,
|
|
71
34
|
SourceCodeRepositoryBranch.SourceCodeRepository.Provider
|
|
72
35
|
FROM WorkItem
|
|
73
36
|
WHERE ${whereClause}
|
|
@@ -77,24 +40,12 @@ export async function fetchWorkItemDetail(connection, filter) {
|
|
|
77
40
|
throw new Error(`Work item '${identifier}' not found.`);
|
|
78
41
|
}
|
|
79
42
|
const provider = normalizeProvider(record.SourceCodeRepositoryBranch?.SourceCodeRepository?.Provider);
|
|
80
|
-
let repoOwner = record.SourceCodeRepositoryBranch?.SourceCodeRepository?.RepositoryOwner ?? undefined;
|
|
81
|
-
const vcsType = providerToVcsType(provider);
|
|
82
|
-
if (vcsType && !repoOwner) {
|
|
83
|
-
try {
|
|
84
|
-
repoOwner = (await fetchOwnerByVcsType(connection, vcsType)) ?? undefined;
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
// owner lookup is best-effort
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
43
|
const detail = {
|
|
91
44
|
workItemId: record.Id,
|
|
92
45
|
workItemName: record.Name,
|
|
93
46
|
subject: record.Subject ?? '',
|
|
94
47
|
branchName: record.SourceCodeRepositoryBranch?.Name ?? undefined,
|
|
95
48
|
projectId: record.DevopsProjectId,
|
|
96
|
-
repoOwner,
|
|
97
|
-
repoName: record.SourceCodeRepositoryBranch?.SourceCodeRepository?.Name ?? undefined,
|
|
98
49
|
provider,
|
|
99
50
|
};
|
|
100
51
|
const pipelineId = await getPipelineIdForProject(connection, record.DevopsProjectId);
|
|
@@ -110,95 +61,72 @@ export async function fetchWorkItemDetail(connection, filter) {
|
|
|
110
61
|
}
|
|
111
62
|
return detail;
|
|
112
63
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
64
|
+
function extractPrError(response) {
|
|
65
|
+
const raw = String(response.errorMessage ?? response.error ?? response.message ?? 'Pull request creation failed');
|
|
66
|
+
// Try to extract inner VCS error from "REVIEW_CREATION_FAILED:Failed to create pull request: ..."
|
|
67
|
+
const innerMatch = raw.match(/Failed to create pull request:\s*(.+)/s);
|
|
68
|
+
const inner = innerMatch ? innerMatch[1].trim() : raw;
|
|
69
|
+
// Try to parse JSON error body from named credential callout responses
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(inner);
|
|
72
|
+
const msg = parsed?.error?.message ?? parsed?.message;
|
|
73
|
+
if (msg)
|
|
74
|
+
return String(msg);
|
|
120
75
|
}
|
|
121
|
-
|
|
122
|
-
|
|
76
|
+
catch {
|
|
77
|
+
// not JSON, use as-is
|
|
123
78
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
async function createGitHubPullRequest(params) {
|
|
127
|
-
const { owner, repo, head, base, title, body, token } = params;
|
|
128
|
-
const url = `https://api.github.com/repos/${owner}/${repo}/pulls`;
|
|
129
|
-
const response = await fetch(url, {
|
|
130
|
-
method: 'POST',
|
|
131
|
-
headers: {
|
|
132
|
-
Authorization: `Bearer ${token}`,
|
|
133
|
-
Accept: 'application/vnd.github+json',
|
|
134
|
-
'Content-Type': 'application/json',
|
|
135
|
-
'X-GitHub-Api-Version': '2022-11-28',
|
|
136
|
-
},
|
|
137
|
-
body: JSON.stringify({ title, body: body ?? '', head, base }),
|
|
138
|
-
});
|
|
139
|
-
const data = (await response.json());
|
|
140
|
-
if (!response.ok) {
|
|
141
|
-
const errors = Array.isArray(data.errors)
|
|
142
|
-
? data.errors.map((e) => e.message ?? JSON.stringify(e)).join('; ')
|
|
143
|
-
: undefined;
|
|
144
|
-
const msg = data.message ?? `HTTP ${response.status}`;
|
|
145
|
-
throw new Error(errors ? `${msg}: ${errors}` : msg);
|
|
79
|
+
if (inner.includes('no changes')) {
|
|
80
|
+
return 'The branch has no commits ahead of the target branch. Push your changes and try again.';
|
|
146
81
|
}
|
|
147
|
-
return
|
|
148
|
-
success: true,
|
|
149
|
-
title: data.title,
|
|
150
|
-
url: data.html_url,
|
|
151
|
-
sourceBranch: head,
|
|
152
|
-
targetBranch: base,
|
|
153
|
-
};
|
|
82
|
+
return inner;
|
|
154
83
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Creates a pull request via the Salesforce Connect API.
|
|
86
|
+
* POST /connect/devops/workItems/{workItemId}/review
|
|
87
|
+
* Salesforce handles VCS authentication and workspace resolution.
|
|
88
|
+
*/
|
|
89
|
+
export async function createPullRequest(connection, workItemId) {
|
|
90
|
+
const path = `/services/data/v${connection.getApiVersion()}/connect/devops/workItems/${workItemId}/review`;
|
|
91
|
+
let response;
|
|
92
|
+
try {
|
|
93
|
+
response = await connection.request({
|
|
94
|
+
method: 'POST',
|
|
95
|
+
url: path,
|
|
96
|
+
body: JSON.stringify({}),
|
|
97
|
+
headers: { 'Content-Type': 'application/json' },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
102
|
+
throw new Error(extractPrError({ errorMessage: raw }));
|
|
103
|
+
}
|
|
104
|
+
const isError = response.status === 'Error' || response.success === false || !!response.errorMessage;
|
|
105
|
+
if (isError) {
|
|
106
|
+
throw new Error(extractPrError(response));
|
|
175
107
|
}
|
|
176
|
-
const links = data.links;
|
|
177
108
|
return {
|
|
178
109
|
success: true,
|
|
179
|
-
|
|
180
|
-
url: links?.html?.href ?? data.url ?? '',
|
|
181
|
-
sourceBranch: head,
|
|
182
|
-
targetBranch: base,
|
|
110
|
+
url: response.reviewUrl,
|
|
183
111
|
};
|
|
184
112
|
}
|
|
185
113
|
/**
|
|
186
|
-
* Attempts to resolve a
|
|
187
|
-
*
|
|
114
|
+
* Attempts to resolve a GitHub authentication token from the environment or the gh CLI.
|
|
115
|
+
* Used by pipeline create for pre-flight owner validation.
|
|
188
116
|
*/
|
|
189
|
-
export
|
|
117
|
+
export function resolveGitHubToken() {
|
|
190
118
|
const envToken = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
|
|
191
119
|
if (envToken)
|
|
192
|
-
return envToken;
|
|
120
|
+
return Promise.resolve(envToken);
|
|
193
121
|
try {
|
|
194
|
-
|
|
122
|
+
// execSync with a fixed string — no user input, no injection risk
|
|
195
123
|
const token = execSync('gh auth token', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
196
124
|
if (token)
|
|
197
|
-
return token;
|
|
125
|
+
return Promise.resolve(token);
|
|
198
126
|
}
|
|
199
127
|
catch {
|
|
200
128
|
// gh CLI not installed or not authenticated
|
|
201
129
|
}
|
|
202
|
-
return undefined;
|
|
130
|
+
return Promise.resolve(undefined);
|
|
203
131
|
}
|
|
204
132
|
//# sourceMappingURL=createPullRequest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPullRequest.js","sourceRoot":"","sources":["../../src/utils/createPullRequest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"createPullRequest.js","sourceRoot":"","sources":["../../src/utils/createPullRequest.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,32 +3,30 @@ export type WorkItemContext = {
|
|
|
3
3
|
workItemId: string;
|
|
4
4
|
projectId: string;
|
|
5
5
|
};
|
|
6
|
-
export type
|
|
6
|
+
export type UpdateWorkItemParams = {
|
|
7
7
|
connection: Connection;
|
|
8
8
|
workItemId: string;
|
|
9
9
|
projectId: string;
|
|
10
|
-
status
|
|
10
|
+
status?: string;
|
|
11
|
+
subject?: string;
|
|
12
|
+
description?: string;
|
|
11
13
|
};
|
|
12
|
-
export type
|
|
14
|
+
export type UpdateWorkItemResult = {
|
|
13
15
|
success: boolean;
|
|
14
16
|
workItemId: string;
|
|
15
17
|
workItemName?: string;
|
|
16
18
|
status?: string;
|
|
19
|
+
subject?: string;
|
|
20
|
+
description?: string;
|
|
17
21
|
error?: string;
|
|
18
22
|
};
|
|
19
|
-
/**
|
|
20
|
-
* Resolves a work item's Salesforce ID and project ID from its Name (e.g. WI-000001) via SOQL.
|
|
21
|
-
*/
|
|
22
|
-
export declare function resolveWorkItemByName(connection: Connection, workItemName: string): Promise<WorkItemContext>;
|
|
23
|
-
/**
|
|
24
|
-
* Fetches the project ID for a given work item ID via SOQL.
|
|
25
|
-
*/
|
|
26
|
-
export declare function resolveProjectIdForWorkItem(connection: Connection, workItemId: string): Promise<string>;
|
|
27
23
|
export declare const ALLOWED_STATUSES: readonly ["In Progress", "Ready to Promote"];
|
|
28
24
|
export type AllowedStatus = (typeof ALLOWED_STATUSES)[number];
|
|
29
25
|
export declare function toApiStatus(status: string): string;
|
|
26
|
+
export declare function resolveWorkItemByName(connection: Connection, workItemName: string): Promise<WorkItemContext>;
|
|
27
|
+
export declare function resolveProjectIdForWorkItem(connection: Connection, workItemId: string): Promise<string>;
|
|
30
28
|
/**
|
|
31
|
-
* Updates
|
|
32
|
-
*
|
|
29
|
+
* Updates fields on a DevOps Center work item via the Connect API.
|
|
30
|
+
* PATCH /services/data/v{version}/connect/devops/projects/{projectId}/workitem/{workItemId}
|
|
33
31
|
*/
|
|
34
|
-
export declare function
|
|
32
|
+
export declare function updateWorkItem(params: UpdateWorkItemParams): Promise<UpdateWorkItemResult>;
|
|
@@ -13,9 +13,18 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
export const ALLOWED_STATUSES = ['In Progress', 'Ready to Promote'];
|
|
17
|
+
const STATUS_LABEL_TO_API = {
|
|
18
|
+
'in progress': 'IN_PROGRESS',
|
|
19
|
+
'ready to promote': 'READY_TO_PROMOTE',
|
|
20
|
+
};
|
|
21
|
+
export function toApiStatus(status) {
|
|
22
|
+
const apiStatus = STATUS_LABEL_TO_API[status.toLowerCase()];
|
|
23
|
+
if (!apiStatus) {
|
|
24
|
+
throw new Error(`Invalid status "${status}". Allowed values: ${ALLOWED_STATUSES.join(', ')}`);
|
|
25
|
+
}
|
|
26
|
+
return apiStatus;
|
|
27
|
+
}
|
|
19
28
|
export async function resolveWorkItemByName(connection, workItemName) {
|
|
20
29
|
const result = await connection.query(`SELECT Id, DevopsProjectId FROM WorkItem WHERE Name = '${workItemName}' LIMIT 1`);
|
|
21
30
|
const record = (result.records ?? [])[0];
|
|
@@ -24,9 +33,6 @@ export async function resolveWorkItemByName(connection, workItemName) {
|
|
|
24
33
|
}
|
|
25
34
|
return { workItemId: record.Id, projectId: record.DevopsProjectId };
|
|
26
35
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Fetches the project ID for a given work item ID via SOQL.
|
|
29
|
-
*/
|
|
30
36
|
export async function resolveProjectIdForWorkItem(connection, workItemId) {
|
|
31
37
|
const result = await connection.query(`SELECT DevopsProjectId FROM WorkItem WHERE Id = '${workItemId}' LIMIT 1`);
|
|
32
38
|
const record = (result.records ?? [])[0];
|
|
@@ -35,37 +41,33 @@ export async function resolveProjectIdForWorkItem(connection, workItemId) {
|
|
|
35
41
|
}
|
|
36
42
|
return record.DevopsProjectId;
|
|
37
43
|
}
|
|
38
|
-
export const ALLOWED_STATUSES = ['In Progress', 'Ready to Promote'];
|
|
39
|
-
const STATUS_LABEL_TO_API = {
|
|
40
|
-
'in progress': 'IN_PROGRESS',
|
|
41
|
-
'ready to promote': 'READY_TO_PROMOTE',
|
|
42
|
-
};
|
|
43
|
-
export function toApiStatus(status) {
|
|
44
|
-
const apiStatus = STATUS_LABEL_TO_API[status.toLowerCase()];
|
|
45
|
-
if (!apiStatus) {
|
|
46
|
-
throw new Error(`Invalid status "${status}". Allowed values: ${ALLOWED_STATUSES.join(', ')}`);
|
|
47
|
-
}
|
|
48
|
-
return apiStatus;
|
|
49
|
-
}
|
|
50
44
|
/**
|
|
51
|
-
* Updates
|
|
52
|
-
*
|
|
45
|
+
* Updates fields on a DevOps Center work item via the Connect API.
|
|
46
|
+
* PATCH /services/data/v{version}/connect/devops/projects/{projectId}/workitem/{workItemId}
|
|
53
47
|
*/
|
|
54
|
-
export async function
|
|
55
|
-
const { connection, workItemId, projectId, status } = params;
|
|
48
|
+
export async function updateWorkItem(params) {
|
|
49
|
+
const { connection, workItemId, projectId, status, subject, description } = params;
|
|
56
50
|
const path = `/services/data/v${connection.getApiVersion()}/connect/devops/projects/${projectId}/workitem/${workItemId}`;
|
|
57
|
-
const
|
|
51
|
+
const payload = {};
|
|
52
|
+
if (status !== undefined)
|
|
53
|
+
payload.status = toApiStatus(status);
|
|
54
|
+
if (subject !== undefined)
|
|
55
|
+
payload.subject = subject;
|
|
56
|
+
if (description !== undefined)
|
|
57
|
+
payload.description = description;
|
|
58
58
|
const response = await connection.request({
|
|
59
59
|
method: 'PATCH',
|
|
60
60
|
url: path,
|
|
61
|
-
body,
|
|
61
|
+
body: JSON.stringify(payload),
|
|
62
62
|
headers: { 'Content-Type': 'application/json' },
|
|
63
63
|
});
|
|
64
64
|
const data = response ?? {};
|
|
65
65
|
return {
|
|
66
66
|
success: true,
|
|
67
67
|
workItemId,
|
|
68
|
-
status: (data.status ?? data.Status ?? status),
|
|
68
|
+
status: status !== undefined ? (data.status ?? data.Status ?? status) : undefined,
|
|
69
|
+
subject: subject !== undefined ? (data.subject ?? data.Subject ?? subject) : undefined,
|
|
70
|
+
description: description !== undefined ? (data.description ?? data.Description ?? description) : undefined,
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
|
-
//# sourceMappingURL=
|
|
73
|
+
//# sourceMappingURL=updateWorkItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateWorkItem.js","sourceRoot":"","sources":["../../src/utils/updateWorkItem.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,11 +28,15 @@ Create a repository if it doesn't exist.
|
|
|
28
28
|
|
|
29
29
|
# flags.repo-owner.summary
|
|
30
30
|
|
|
31
|
-
Owner (organization or user) of the repository. Required when creating a repository using '--create-repo'.
|
|
31
|
+
Owner (organization or user) of the GitHub repository. Required when creating a GitHub repository using '--create-repo'.
|
|
32
32
|
|
|
33
|
-
# flags.bitbucket-
|
|
33
|
+
# flags.bitbucket-workspace.summary
|
|
34
34
|
|
|
35
|
-
Bitbucket
|
|
35
|
+
Bitbucket workspace that will own the repository. Required when creating a Bitbucket repository using '--create-repo'.
|
|
36
|
+
|
|
37
|
+
# flags.bitbucket-project-key.summary
|
|
38
|
+
|
|
39
|
+
Bitbucket project key to associate with the repository. Optional when creating a Bitbucket repository using '--create-repo'.
|
|
36
40
|
|
|
37
41
|
# flags.description.summary
|
|
38
42
|
|
|
@@ -48,14 +52,26 @@ Description of the pipeline.
|
|
|
48
52
|
|
|
49
53
|
<%= config.bin %> <%= command.id %> --target-org my-devops-org --name "Release Pipeline" --repo my-new-repo --repo-type github --repo-owner myorg --create-repo
|
|
50
54
|
|
|
51
|
-
- Create a pipeline
|
|
55
|
+
- Create a pipeline and create a new Bitbucket repository.
|
|
56
|
+
|
|
57
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --name "Release Pipeline" --repo my-new-repo --repo-type bitbucket --bitbucket-workspace myworkspace --bitbucket-project-key PROJ --create-repo
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
- Create a pipeline with a description and associate it with an existing Bitbucket repository.
|
|
60
|
+
|
|
61
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --name "Release Pipeline" --repo https://bitbucket.org/myworkspace/myrepo --description "Main CI/CD pipeline for production releases"
|
|
54
62
|
|
|
55
63
|
# error.RepoTypeRequired
|
|
56
64
|
|
|
57
65
|
The --repo-type flag is required when using --create-repo. Specify --repo-type github or --repo-type bitbucket.
|
|
58
66
|
|
|
67
|
+
# error.RepoOwnerNotFound
|
|
68
|
+
|
|
69
|
+
The repository "%s" could not be initialized because the --repo-owner does not exist or is not accessible on GitHub. Verify the --repo-owner value is a valid GitHub organization or user.
|
|
70
|
+
|
|
71
|
+
# error.RepoNameAlreadyExists
|
|
72
|
+
|
|
73
|
+
A repository named "%s" already exists on this account. Choose a different name or use the existing repository URL with --repo instead of --create-repo.
|
|
74
|
+
|
|
59
75
|
# error.RepoCreationFailed
|
|
60
76
|
|
|
61
77
|
Failed to create repository "%s". Verify the --repo-owner has permission to create repositories and the repository name is available. Details: %s
|
|
@@ -70,7 +86,11 @@ Failed to validate repository "%s". When using an existing repository, provide t
|
|
|
70
86
|
|
|
71
87
|
# error.RepoOwnerRequired
|
|
72
88
|
|
|
73
|
-
The --repo-owner flag is required when
|
|
89
|
+
The --repo-owner flag is required when creating a GitHub repository with --create-repo. Specify the GitHub organization or user that will own the repository.
|
|
90
|
+
|
|
91
|
+
# error.BitbucketWorkspaceRequired
|
|
92
|
+
|
|
93
|
+
The --bitbucket-workspace flag is required when creating a Bitbucket repository with --create-repo. Specify the Bitbucket workspace that will own the repository.
|
|
74
94
|
|
|
75
95
|
# error.VcsCredentialsMissing
|
|
76
96
|
|
|
@@ -4,7 +4,7 @@ Create a pull request for a work item branch.
|
|
|
4
4
|
|
|
5
5
|
# description
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Creates a pull request via the Salesforce DevOps Center API, using the VCS credentials stored in the org. Works with GitHub and Bitbucket without requiring local VCS authentication.
|
|
8
8
|
|
|
9
9
|
# flags.work-item-name.summary
|
|
10
10
|
|
|
@@ -14,44 +14,20 @@ Name of the work item, such as WI-000001.
|
|
|
14
14
|
|
|
15
15
|
ID of the work item.
|
|
16
16
|
|
|
17
|
-
# flags.
|
|
18
|
-
|
|
19
|
-
Title of the pull request.
|
|
20
|
-
|
|
21
|
-
# flags.body.summary
|
|
17
|
+
# flags.target-org.summary
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
Username or alias of the DevOps Center org.
|
|
24
20
|
|
|
25
21
|
# examples
|
|
26
22
|
|
|
27
|
-
- Create a pull request for a work item
|
|
23
|
+
- Create a pull request for a work item.
|
|
28
24
|
|
|
29
25
|
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-name WI-000001
|
|
30
26
|
|
|
31
|
-
- Create a pull request
|
|
27
|
+
- Create a pull request using the work item ID.
|
|
32
28
|
|
|
33
|
-
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-id 0Wx000000000001
|
|
29
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-id 0Wx000000000001
|
|
34
30
|
|
|
35
31
|
# error.NoBranch
|
|
36
32
|
|
|
37
33
|
Work item %s doesn't have an associated branch. Mark the work item as In Progress to create a branch, then try again.
|
|
38
|
-
|
|
39
|
-
# error.NoRepo
|
|
40
|
-
|
|
41
|
-
Work item %s doesn't have an associated repository. Verify the project is connected to a source control repository and try again.
|
|
42
|
-
|
|
43
|
-
# error.NoTargetBranch
|
|
44
|
-
|
|
45
|
-
Unable to determine the target branch for work item %s. Verify the pipeline stages are configured correctly.
|
|
46
|
-
|
|
47
|
-
# error.NoProvider
|
|
48
|
-
|
|
49
|
-
Unable to determine the VCS provider for work item %s. Verify the project is connected to a supported source control provider (GitHub or Bitbucket).
|
|
50
|
-
|
|
51
|
-
# flags.target-org.summary
|
|
52
|
-
|
|
53
|
-
Username or alias of the DevOps Center org.
|
|
54
|
-
|
|
55
|
-
# error.NoToken
|
|
56
|
-
|
|
57
|
-
No authentication token found for %s. For GitHub, set the GITHUB_TOKEN environment variable or run "gh auth login". For Bitbucket, set the BITBUCKET_TOKEN environment variable.
|
|
@@ -48,6 +48,10 @@ Waiting for authentication to complete...
|
|
|
48
48
|
|
|
49
49
|
Successfully added environment to the stage.
|
|
50
50
|
|
|
51
|
+
# error.PipelineAlreadyActive
|
|
52
|
+
|
|
53
|
+
Pipeline %s is already active. Environments can only be added to inactive pipelines.
|
|
54
|
+
|
|
51
55
|
# error.StageNotFound
|
|
52
56
|
|
|
53
57
|
Pipeline stage "%s" doesn't exist in pipeline "%s". Check the stage ID and try again.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Update a work item in DevOps Center.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Update the subject, description, or status of a work item. At least one of --subject, --description, or --status must be provided.
|
|
8
|
+
|
|
9
|
+
# flags.work-item-name.summary
|
|
10
|
+
|
|
11
|
+
Name of the work item, such as WI-000001.
|
|
12
|
+
|
|
13
|
+
# flags.work-item-id.summary
|
|
14
|
+
|
|
15
|
+
ID of the work item.
|
|
16
|
+
|
|
17
|
+
# flags.subject.summary
|
|
18
|
+
|
|
19
|
+
New subject for the work item.
|
|
20
|
+
|
|
21
|
+
# flags.description.summary
|
|
22
|
+
|
|
23
|
+
New description for the work item.
|
|
24
|
+
|
|
25
|
+
# flags.status.summary
|
|
26
|
+
|
|
27
|
+
New status for the work item. Allowed values: "In Progress", "Ready to Promote".
|
|
28
|
+
|
|
29
|
+
# examples
|
|
30
|
+
|
|
31
|
+
- Update the subject of a work item by name:
|
|
32
|
+
|
|
33
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-name WI-000001 --subject "Fix login bug"
|
|
34
|
+
|
|
35
|
+
- Update the status of a work item by ID:
|
|
36
|
+
|
|
37
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-id 0Wx000000000001 --status "In Progress"
|
|
38
|
+
|
|
39
|
+
- Update multiple fields at once:
|
|
40
|
+
|
|
41
|
+
<%= config.bin %> <%= command.id %> --target-org my-devops-org --work-item-name WI-000001 --subject "Fix login bug" --description "Users can't log in on mobile" --status "In Progress"
|
|
42
|
+
|
|
43
|
+
# error.NoFieldsProvided
|
|
44
|
+
|
|
45
|
+
Provide at least one of --subject, --description, or --status.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/plugin-devops-center",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/plugin-devops-center",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.4.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@jsforce/jsforce-node": "^3",
|