Skip to content

Commit 50fb11b

Browse files
azp: enhance azure pipelines extension and publish new preview (#594)
1 parent 1c711fd commit 50fb11b

File tree

7 files changed

+188
-91
lines changed

7 files changed

+188
-91
lines changed

Diff for: src/azure-pipelines-vscode-ext/CHANGELOG.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
### v0.2.14
1+
### v0.3.1
2+
- fix -q flag had no space between cli command and hypen
3+
4+
### v0.3.0 (Preview)
25
- fix auto complete regression for block mappings
36
- add auto completion tests for debugging purposes
4-
- fix error of Unrecognized function
7+
- fix error message of Unrecognized function
8+
- add `Copy Linter Task as Cli Command for use in CI or debugging` Command to get a Runner.Client CLI style command
9+
- add `create-task-log-files` Setting to create an Output Log file in Outputs for new Tasks e.g. handy for Issue reports or debugging
10+
- save new Tasks after providing inputs
11+
- support stringList parameter type
12+
- prefer multiple choice and plain text prompt over a YAML string input
13+
- Symbols like `*`, `&`, `'` and `"` are no longer interpreted
514

615
### v0.2.13
716
- add more tests

Diff for: src/azure-pipelines-vscode-ext/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,21 @@ stages:
184184
}'
185185
```
186186
187+
### Run the Linter Task using a custom keybind
188+
189+
Follow https://code.visualstudio.com/docs/configure/keybindings#_advanced-customization then use this as example
190+
```json
191+
[
192+
{
193+
"key": "ctrl+cmd+g",
194+
"command": "workbench.action.tasks.runTask",
195+
"args": "Expand Pipeline demo2/pipeline.yml"
196+
}
197+
]
198+
```
199+
200+
`Expand Pipeline demo2/pipeline.yml` is an example label of the task in your `.vscode/tasks.json` file.
201+
187202
## Pro
188203
- Make changes in multiple dependent template files and show a live preview
189204
- Everything is done locally and works offline

Diff for: src/azure-pipelines-vscode-ext/index.js

+132-85
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,40 @@ import { AzurePipelinesDebugSession } from "./azure-pipelines-debug";
44
import { integer, Position } from "vscode-languageclient";
55
import jsYaml from "js-yaml";
66
import { applyEdits, modify } from "jsonc-parser";
7+
import vsVars from "vscode-variables";
8+
9+
function joinPath(l, r) {
10+
return l ? l + "/" + r : r;
11+
}
12+
13+
function cliQuote(str) {
14+
if(str.includes(" ") || str.includes("$") || str.includes("\t") || str.includes("\n") || str.includes("\r") || str.includes('"')) {
15+
return `'${str.replace(/'/g, "'\\''")}'`;
16+
}
17+
return str;
18+
}
19+
20+
async function locateExternalRepoUrl(rawbase, filename) {
21+
try {
22+
var base = vscode.Uri.parse(rawbase, true);
23+
var stat = await vscode.workspace.fs.stat(base);
24+
if(stat.type === vscode.FileType.Directory) {
25+
return base.with({ path: joinPath(base.path, filename) });
26+
}
27+
} catch {
28+
29+
}
30+
try {
31+
var base = vscode.Uri.file(rawbase);
32+
var stat = await vscode.workspace.fs.stat(base);
33+
if(stat.type === vscode.FileType.Directory) {
34+
return base.with({ path: joinPath(base.path, filename) });
35+
}
36+
} catch {
37+
38+
}
39+
throw Error(`Cannot locate: ${rawbase}`);
40+
}
741

842
/**
943
* @param {vscode.ExtensionContext} context
@@ -25,28 +59,6 @@ function activate(context) {
2559
return virtualFiles[uri.path];
2660
}
2761
});
28-
var joinPath = (l, r) => l ? l + "/" + r : r;
29-
var locateExternalRepoUrl = async (rawbase, filename) => {
30-
try {
31-
var base = vscode.Uri.parse(rawbase, true);
32-
var stat = await vscode.workspace.fs.stat(base);
33-
if(stat.type === vscode.FileType.Directory) {
34-
return base.with({ path: joinPath(base.path, filename) });
35-
}
36-
} catch {
37-
38-
}
39-
try {
40-
var base = vscode.Uri.file(rawbase);
41-
var stat = await vscode.workspace.fs.stat(base);
42-
if(stat.type === vscode.FileType.Directory) {
43-
return base.with({ path: joinPath(base.path, filename) });
44-
}
45-
} catch {
46-
47-
}
48-
throw Error(`Cannot locate: ${rawbase}`);
49-
};
5062
var loadingPromise = null;
5163
var runtimePromise = () => loadingPromise ??= vscode.window.withProgress({
5264
location: vscode.ProgressLocation.Notification,
@@ -326,69 +338,7 @@ function activate(context) {
326338
}
327339

328340
var runtime = await runtimePromise();
329-
var base = null;
330-
331-
var skipCurrentEditor = false;
332-
var filename = null
333-
if(fspathname) {
334-
skipCurrentEditor = true;
335-
var uris = [vscode.Uri.parse(fspathname), vscode.Uri.file(fspathname)];
336-
for(var current of uris) {
337-
var rbase = vscode.workspace.getWorkspaceFolder(current);
338-
var name = vscode.workspace.asRelativePath(current, false);
339-
if(rbase && name) {
340-
base = rbase.uri;
341-
filename = name;
342-
break;
343-
}
344-
}
345-
if(filename == null) {
346-
for(var workspace of (vscode.workspace.workspaceFolders || [])) {
347-
// Normalize
348-
var nativepathname = vscode.Uri.file(fspathname).fsPath;
349-
if(nativepathname.startsWith(workspace.uri.fsPath)) {
350-
base = workspace.uri;
351-
filename = vscode.workspace.asRelativePath(workspace.uri.with({path: joinPath(workspace.uri.path, nativepathname.substring(workspace.uri.fsPath.length).replace(/[\\\/]+/g, "/"))}), false);
352-
break;
353-
}
354-
}
355-
}
356-
if(filename == null) {
357-
// untitled uris will land here
358-
var current = vscode.Uri.parse(fspathname);
359-
for(var workspace of (vscode.workspace.workspaceFolders || [])) {
360-
var workspacePath = workspace.uri.path.replace(/\/*$/, "/");
361-
if(workspace.uri.scheme === current.scheme && workspace.uri.authority === current.authority && current.path.startsWith(workspacePath)) {
362-
base = workspace.uri;
363-
filename = current.path.substring(workspacePath.length);
364-
break;
365-
}
366-
}
367-
var li = current.path.lastIndexOf("/");
368-
base ??= current.with({ path: current.path.substring(0, li)});
369-
filename ??= current.path.substring(li + 1);
370-
try {
371-
await vscode.workspace.fs.stat(current);
372-
} catch {
373-
// untitled uris cannot be read by readFile
374-
skipCurrentEditor = false;
375-
}
376-
}
377-
} else {
378-
filename = null;
379-
var current = textEditor.document.uri;
380-
for(var workspace of (vscode.workspace.workspaceFolders || [])) {
381-
var workspacePath = workspace.uri.path.replace(/\/*$/, "/");
382-
if(workspace.uri.scheme === current.scheme && workspace.uri.authority === current.authority && current.path.startsWith(workspacePath)) {
383-
base = workspace.uri;
384-
filename = current.path.substring(workspacePath.length);
385-
break;
386-
}
387-
}
388-
var li = current.path.lastIndexOf("/");
389-
base ??= current.with({ path: current.path.substring(0, li)});
390-
filename ??= current.path.substring(li + 1);
391-
}
341+
var { name, base, skipCurrentEditor, filename } = await locatePipeline(fspathname, name, textEditor);
392342
var handle = { hasErrors: false, base: base, skipCurrentEditor: skipCurrentEditor, textEditor: textEditor, filename: filename, repositories: repositories, parameters: parameters, error: (async jsonex => {
393343
if(autocompletelist?.disableErrors) {
394344
return;
@@ -689,6 +639,23 @@ function activate(context) {
689639

690640
context.subscriptions.push(vscode.commands.registerCommand('extension.validateAzurePipeline', () => validateAzurePipelineCommand()));
691641

642+
context.subscriptions.push(vscode.commands.registerCommand('azure-pipelines-vscode-ext.copyTaskAsCommand', () => {
643+
vscode.tasks.fetchTasks({ type: "azure-pipelines-vscode-ext" }).then(tasks =>
644+
vscode.window.showQuickPick(tasks.filter(t => t.definition.program).map(t => t.name), { placeHolder: "Select Task to copy as Runner.Client Command" }).then(async name => {
645+
if(name) {
646+
var task = tasks.find(t => t.name === name);
647+
if(task) {
648+
var { filename } = await locatePipeline(vsVars(task.definition.program), null, null);
649+
let quiet = task.definition.preview ? " -q" : "";
650+
await vscode.env.clipboard.writeText(`Runner.Client azexpand${quiet} -W ${cliQuote(filename)} ${task.definition.parameters ? Object.entries(task.definition.parameters).reduce((p, c) => `${p} --input ${cliQuote(`${c[0]}=${typeof c[1] === 'object' ? JSON.stringify(c[1]) : c[1]}`)}`, "") : ""}${task.definition.variables ? Object.entries(task.definition.variables).reduce((p, c) => `${p} --var ${cliQuote(`${c[0]}=${c[1]}'`)}`, "") : ""}${task.definition.repositories ? Object.entries(task.definition.repositories).reduce((p, c) => `${p} --local-repository ${cliQuote(`${c[0]}=${c[1]}`)}`, "") : ""}`);
651+
await vscode.window.showInformationMessage("Copied to clipboard");
652+
return;
653+
}
654+
}
655+
await vscode.window.showErrorMessage("No Task selected");
656+
}).catch(err => vscode.window.showErrorMessage(err.toString())));
657+
}));
658+
692659
var statusbar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
693660
context.subscriptions.push(statusbar);
694661
statusbar.tooltip = "Configure this Icon in Settings";
@@ -1026,6 +993,19 @@ function activate(context) {
1026993
warn: message => writeEmitter.fire("\x1b[33m[warn]" + message.replace(/\r?\n/g, "\r\n") + "\x1b[0m\r\n"),
1027994
error: message => writeEmitter.fire("\x1b[31m[error]" + message.replace(/\r?\n/g, "\r\n") + "\x1b[0m\r\n"),
1028995
};
996+
let config = vscode.workspace.getConfiguration("azure-pipelines-vscode-ext");
997+
if(config.get("create-task-log-files")) {
998+
let taskChannel = vscode.window.createOutputChannel(self.name, { log: true });
999+
self.disposables.push(taskChannel);
1000+
for(var t in task) {
1001+
let type = t;
1002+
let org = task[type];
1003+
task[type] = message => {
1004+
taskChannel[type](message);
1005+
org(message);
1006+
}
1007+
}
1008+
}
10291009
var requestReOpen = true;
10301010
var documentClosed = true;
10311011
var doc = null;
@@ -1207,6 +1187,73 @@ function activate(context) {
12071187
}));
12081188
}
12091189

1190+
async function locatePipeline(fspathname, name, textEditor) {
1191+
var base = null;
1192+
1193+
var skipCurrentEditor = false;
1194+
var filename = null;
1195+
if (fspathname) {
1196+
skipCurrentEditor = true;
1197+
var uris = [vscode.Uri.parse(fspathname), vscode.Uri.file(fspathname)];
1198+
for (var current of uris) {
1199+
var rbase = vscode.workspace.getWorkspaceFolder(current);
1200+
var name = vscode.workspace.asRelativePath(current, false);
1201+
if (rbase && name) {
1202+
base = rbase.uri;
1203+
filename = name;
1204+
break;
1205+
}
1206+
}
1207+
if (filename == null) {
1208+
for (var workspace of (vscode.workspace.workspaceFolders || [])) {
1209+
// Normalize
1210+
var nativepathname = vscode.Uri.file(fspathname).fsPath;
1211+
if (nativepathname.startsWith(workspace.uri.fsPath)) {
1212+
base = workspace.uri;
1213+
filename = vscode.workspace.asRelativePath(workspace.uri.with({ path: joinPath(workspace.uri.path, nativepathname.substring(workspace.uri.fsPath.length).replace(/[\\\/]+/g, "/")) }), false);
1214+
break;
1215+
}
1216+
}
1217+
}
1218+
if (filename == null) {
1219+
// untitled uris will land here
1220+
var current = vscode.Uri.parse(fspathname);
1221+
for (var workspace of (vscode.workspace.workspaceFolders || [])) {
1222+
var workspacePath = workspace.uri.path.replace(/\/*$/, "/");
1223+
if (workspace.uri.scheme === current.scheme && workspace.uri.authority === current.authority && current.path.startsWith(workspacePath)) {
1224+
base = workspace.uri;
1225+
filename = current.path.substring(workspacePath.length);
1226+
break;
1227+
}
1228+
}
1229+
var li = current.path.lastIndexOf("/");
1230+
base ??= current.with({ path: current.path.substring(0, li) });
1231+
filename ??= current.path.substring(li + 1);
1232+
try {
1233+
await vscode.workspace.fs.stat(current);
1234+
} catch {
1235+
// untitled uris cannot be read by readFile
1236+
skipCurrentEditor = false;
1237+
}
1238+
}
1239+
} else if(textEditor !== null) {
1240+
filename = null;
1241+
var current = textEditor.document.uri;
1242+
for (var workspace of (vscode.workspace.workspaceFolders || [])) {
1243+
var workspacePath = workspace.uri.path.replace(/\/*$/, "/");
1244+
if (workspace.uri.scheme === current.scheme && workspace.uri.authority === current.authority && current.path.startsWith(workspacePath)) {
1245+
base = workspace.uri;
1246+
filename = current.path.substring(workspacePath.length);
1247+
break;
1248+
}
1249+
}
1250+
var li = current.path.lastIndexOf("/");
1251+
base ??= current.with({ path: current.path.substring(0, li) });
1252+
filename ??= current.path.substring(li + 1);
1253+
}
1254+
return { name, base, skipCurrentEditor, filename };
1255+
}
1256+
12101257
// this method is called when your extension is deactivated
12111258
function deactivate() {}
12121259

Diff for: src/azure-pipelines-vscode-ext/os.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function homedir() {
2+
return "/";
3+
}
4+
5+
export function platform() {
6+
return "browser";
7+
}

Diff for: src/azure-pipelines-vscode-ext/package-lock.json

+8-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/azure-pipelines-vscode-ext/package.json

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"Programming Languages"
99
],
1010
"icon": "pipeline-rocket.png",
11-
"version": "0.2.14",
11+
"version": "0.3.1",
1212
"publisher": "christopherhx",
1313
"repository": "https://github.com/ChristopherHX/runner.server",
1414
"engines": {
@@ -41,6 +41,10 @@
4141
"command": "azure-pipelines-vscode-ext.expandAzurePipeline",
4242
"title": "Expand Azure Pipeline",
4343
"shortTitle": "Expand"
44+
},
45+
{
46+
"command": "azure-pipelines-vscode-ext.copyTaskAsCommand",
47+
"title": "Copy Linter Task as Cli Command for use in CI or debugging"
4448
}
4549
],
4650
"menus": {
@@ -148,6 +152,12 @@
148152
"default": false,
149153
"scope": "window",
150154
"description": "Enable currently slow hover content in this web extension"
155+
},
156+
"azure-pipelines-vscode-ext.create-task-log-files": {
157+
"type": "boolean",
158+
"default": false,
159+
"scope": "window",
160+
"description": "Create task log files in VSCode Output Section to inspect the whole task log"
151161
}
152162
}
153163
}
@@ -357,6 +367,7 @@
357367
"jsonc-parser": "^3.3.1",
358368
"ts-loader": "^9.5.0",
359369
"url": "^0.11.3",
360-
"vscode-languageclient": "^9.0.1"
370+
"vscode-languageclient": "^9.0.1",
371+
"vscode-variables": "^1.0.1"
361372
}
362373
}

Diff for: src/azure-pipelines-vscode-ext/webpack.config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const webExtensionConfig = {
2727
assert: require.resolve('assert'),
2828
process: false,
2929
module: false,
30+
os: path.resolve("./os.js"),
3031
}
3132
},
3233
module: {
@@ -54,7 +55,7 @@ const webExtensionConfig = {
5455
plugins: [
5556
new webpack.ProvidePlugin({
5657
process: 'process/browser' // provide a shim for the global `process` variable
57-
})
58+
})
5859
],
5960
externals: {
6061
vscode: 'commonjs vscode' // ignored because it doesn't exist

0 commit comments

Comments
 (0)