Compare commits

..
Author SHA1 Message Date
Andrew Wang 8ed800ed14 Memory Window Test 2021-01-27 15:03:36 -08:00
Andrew Wang 1dddce718c Add command to open Memory Window 2020-08-17 17:48:43 -07:00
1040 changed files with 65744 additions and 120955 deletions
@@ -1,79 +0,0 @@
name: Bug Report - Language Service
description: Create a bug report for IntelliSense, code editing, code navigation, code completion, code formatting, semantic colorization, etc.
body:
- type: markdown
attributes:
value: |
### Is there an existing issue for this?
Please search our [existing issues](https://github.com/microsoft/vscode-cpptools/issues) to see if an issue already exists for the bug you encountered.
Please also review our [documentation](https://code.visualstudio.com/docs/languages/cpp) and [FAQs](https://code.visualstudio.com/docs/cpp/faq-cpp).
- type: textarea
attributes:
label: Environment
description: |
Please provide the information for the following:
- OS and Version
- VS Code Version
- C/C++ Extension Version
- If using SSH remote, specify OS of remote machine
value: |
- OS and Version:
- VS Code Version:
- C/C++ Extension Version:
- If using SSH remote, specify OS of remote machine:
validations:
required: true
- type: textarea
attributes:
label: Bug Summary and Steps to Reproduce
description: |
Please describe the language service issue or language service feature that is not working as expected. Include information about the actual workspace project (for example, is the workspace a single project or multiple projects, size of the project, etc).
Include clear steps on how to reproduce the issue and a description of what you expected to happen.
value: |
Bug Summary:
Steps to reproduce:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
Expected behavior:
validations:
required: true
- type: textarea
attributes:
label: Configuration and Logs
description: |
Please provide your c_cpp_properties.json and logs:
- Configurations in `c_cpp_properties.json`
- Logs from running `C/C++: Log Diagnostics` from the VS Code command palette
- Logs from [the language server logging](https://code.visualstudio.com/docs/cpp/enable-logging-cpp#_enable-logging-for-the-language-server)
render: shell
validations:
required: true
- type: textarea
attributes:
label: Other Extensions
description: If applicable, please list other extensions installed and if the issue persists after disabling other extensions.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: |
Optionally provide other information that will give us more context about the issue you are encountering, such as code sample, screenshots, screen recording of the issue, call stacks, etc.
Providing call stacks:
For bugs like crashes, deadlocks, infinite loops, etc. that we are not able to repro and for which the call stack may be useful, please attach a debugger and/or create a dmp and provide the call stacks. Windows binaries have symbols available in VS Code by setting your "symbolSearchPath" to "https://msdl.microsoft.com/download/symbols".
Instructions for attaching debugger to language service process:
https://github.com/microsoft/vscode-cpptools/wiki/Attaching-debugger-to-cpptools-or-cpptools%E2%80%90srv.
Performance analysis:
For a performance issue see instructions at https://github.com/microsoft/vscode-cpptools/wiki/Troubleshooting-Performance-Issues.
validations:
required: false
-78
View File
@@ -1,78 +0,0 @@
name: Bug Report - Debugger
description: Create a bug report for debugging such as call stack, breakpoints, watch window, launching or attaching to a debuggee.
body:
- type: markdown
attributes:
value: |
### Is there an existing issue for this?
Please search our [existing issues](https://github.com/microsoft/vscode-cpptools/issues) to see if an issue already exists for the bug you encountered.
Please also review our [documentation](https://code.visualstudio.com/docs/languages/cpp) and [FAQs](https://code.visualstudio.com/docs/cpp/faq-cpp).
- type: textarea
attributes:
label: Environment
description: |
Please provide the information for the following:
- OS and version
- VS Code version
- C/C++ extension version
- OS and version of remote machine (if applicable)
- GDB / LLDB version
value: |
- OS and version:
- VS Code:
- C/C++ extension:
- OS and version of remote machine (if applicable):
- GDB / LLDB version:
validations:
required: true
- type: textarea
attributes:
label: Bug Summary and Steps to Reproduce
description: |
Please describe the debugging issue or debugger feature that is not working as expected.
Include clear steps on how to reproduce the issue.
value: |
Bug Summary:
Steps to reproduce:
1. In this environment...
2. With this config...
3. Do '...'
4. See error...
validations:
required: true
- type: textarea
attributes:
label: Debugger Configurations
description: Please provide the debugger configurations from the **tasks.json** and **launch.json** files.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Debugger Logs
description: |
If applicable, please include [logging for the debugger adapter](https://code.visualstudio.com/docs/cpp/enable-logging-cpp#_enable-logging-for-the-debug-adapter) by adding `"logging": { "engineLogging": true, "trace": true, "traceResponse": true }` in the **launch.json** file.
Include logs or error messages from the Debug Console or Output windows.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Other Extensions
description: If applicable, please list other extensions installed and if the issue persists after disabling other extensions.
validations:
required: false
- type: textarea
attributes:
label: Additional Information
description: |
Optionally provide other information that will give us more context about the issue you are encountering, such as a code sample, screenshots, or screen recording of the issue.
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
@@ -1,15 +0,0 @@
name: Feature Request
description: Suggest an idea for the C/C++ extension.
body:
- type: markdown
attributes:
value: |
### Is there an existing request for this feature?
Prior to creating a new feature request, please review our [existing feature requests](https://github.com/microsoft/vscode-cpptools/issues?q=is%3Aopen+is%3Aissue+label%3A%22Feature+Request%22) to avoid duplicates.
- type: textarea
attributes:
label: Feature Request
description: |
Describe the feature you'd like.
validations:
required: true
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Discussion or question
url: https://github.com/microsoft/vscode-cpptools/discussions/new
about: Please use our Discussions board to start a discussion or to ask a question.
+38
View File
@@ -0,0 +1,38 @@
---
name: Debugger
about: Issues pertaining to debugging such as call stack, breakpoints, watch window,
launching or attaching to a debuggee.
title: ''
labels: ''
assignees: ''
---
Type: Debugger
<!----- Input information below ----->
<!--
**Prior to filing an issue, please review:**
- Existing issues at https://github.com/Microsoft/vscode-cpptools/issues
- Our documentation at https://code.visualstudio.com/docs/languages/cpp
- FAQs at https://code.visualstudio.com/docs/cpp/faq-cpp
-->
**Describe the bug**
- OS and Version:
- VS Code Version:
- C/C++ Extension Version:
- Other extensions you installed (and if the issue persists after disabling them):
- A clear and concise description of what the bug is.
**To Reproduce**
*Please include a code sample and `launch.json` configuration.*
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Additional context**
*If applicable, please include logging by adding "logging": { "engineLogging": true, "trace": true, "traceResponse": true } in your `launch.json`*
Add any other context about the problem here including log or error messages in your Debug Console or Output windows.
@@ -0,0 +1,42 @@
---
name: General Extension
about: Issues pertaining to downloading, installing, or building the extension.
title: ''
labels: ''
assignees: ''
---
Type: General
<!----- Input information below ----->
<!--
**Prior to filing an issue, please review:**
- Existing issues at https://github.com/Microsoft/vscode-cpptools/issues
- Our documentation at https://code.visualstudio.com/docs/languages/cpp
- FAQs at https://code.visualstudio.com/docs/cpp/faq-cpp
-->
**Describe the bug**
- OS and Version:
- VS Code Version:
- C/C++ Extension Version:
- Other extensions you installed (and if the issue persists after disabling them):
- A clear and concise description of what the bug is.
**To Reproduce**
*Please include code sample and `task.json` files.*
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here including log messages from the Output window.
@@ -0,0 +1,58 @@
---
name: Language Service
about: 'Issues pertaining to IntelliSense, autocomplete, code editing, etc. '
title: ''
labels: ''
assignees: ''
---
**Type: LanguageService**
<!----- Input information below ----->
<!--
**Prior to filing an issue, please review:**
- Existing issues at https://github.com/Microsoft/vscode-cpptools/issues
- Our documentation at https://code.visualstudio.com/docs/languages/cpp
- FAQs at https://code.visualstudio.com/docs/cpp/faq-cpp
-->
**Describe the bug**
- OS and Version:
- VS Code Version:
- C/C++ Extension Version:
- Other extensions you installed (and if the issue persists after disabling them):
- Does this issue involve using SSH remote to run the extension on a remote machine?:
- A clear and concise description of what the bug is, including information about the workspace (i.e. is the workspace a single project or multiple projects, size of the project, etc).
**Steps to reproduce**
<!-- Provide clear steps to reproduce the behavior: -->
<!-- *The most actionable issue reports include a code sample including configuration files such as c_cpp_properties.json* -->
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
<!-- Please provide the following logs that show diagnostics and debugging information about the language server.
1. Logs from the command `C/C++: Log Diagnostics`
2. Logs from [the language server](https://code.visualstudio.com/docs/cpp/enable-logging-cpp#_enable-logging-for-the-language-server)
-->
<details>
<summary><strong>Logs</strong></summary>
<!-- Note: do not remove empty line after </summary> tag, otherwise the code blocks formatting won't show correctly. -->
```
Insert logs here.
```
</details>
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
<!--
* Call Stacks: For bugs like crashes, deadlocks, infinite loops, etc. that we are not able to repro and for which the call stack may be useful, please attach a debugger and/or create a dmp and provide the call stacks. Windows binaries have symbols available in VS Code by setting your "symbolSearchPath" to "https://msdl.microsoft.com/download/symbols".
-->
-3
View File
@@ -1,3 +0,0 @@
# ignore dependency packages
node_modules
*.js.map
-43
View File
@@ -1,43 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Locker = void 0;
const utils_1 = require("../common/utils");
const ActionBase_1 = require("../common/ActionBase");
class Locker extends ActionBase_1.ActionBase {
constructor(github, daysSinceClose, daysSinceUpdate, labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes) {
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes);
this.github = github;
this.daysSinceClose = daysSinceClose;
this.daysSinceUpdate = daysSinceUpdate;
}
async run() {
const closedTimestamp = (0, utils_1.daysAgoToHumanReadbleDate)(this.daysSinceClose);
const updatedTimestamp = (0, utils_1.daysAgoToHumanReadbleDate)(this.daysSinceUpdate);
const query = this.buildQuery((this.daysSinceClose ? `closed:<${closedTimestamp} ` : "") + (this.daysSinceUpdate ? `updated:<${updatedTimestamp} ` : "") + "is:closed is:unlocked");
for await (const page of this.github.query({ q: query })) {
await Promise.all(page.map(async (issue) => {
const hydrated = await issue.getIssue();
if (!hydrated.locked && hydrated.open === false && this.validateIssue(hydrated)
// TODO: Verify closed and updated timestamps
) {
(0, utils_1.safeLog)(`Locking issue ${hydrated.number}`);
await issue.lockIssue();
}
else {
if (hydrated.locked) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is already locked. Ignoring`);
}
else if (hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}));
}
}
}
exports.Locker = Locker;
//# sourceMappingURL=Locker.js.map
-55
View File
@@ -1,55 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GitHub, Issue } from '../api/api';
import { daysAgoToHumanReadbleDate, safeLog } from '../common/utils';
import { ActionBase } from '../common/ActionBase';
export class Locker extends ActionBase {
constructor(
private github: GitHub,
private daysSinceClose: number,
private daysSinceUpdate: number,
labels?: string,
milestoneName?: string,
milestoneId?: string,
ignoreLabels?: string,
ignoreMilestoneNames?: string,
ignoreMilestoneIds?: string,
minimumVotes?: number,
maximumVotes?: number
)
{
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes);
}
async run() {
const closedTimestamp = daysAgoToHumanReadbleDate(this.daysSinceClose);
const updatedTimestamp = daysAgoToHumanReadbleDate(this.daysSinceUpdate);
const query = this.buildQuery((this.daysSinceClose ? `closed:<${closedTimestamp} ` : "") + (this.daysSinceUpdate ? `updated:<${updatedTimestamp} ` : "") + "is:closed is:unlocked");
for await (const page of this.github.query({ q: query })) {
await Promise.all(
page.map(async (issue) => {
const hydrated = await issue.getIssue();
if (!hydrated.locked && hydrated.open === false && this.validateIssue(hydrated)
// TODO: Verify closed and updated timestamps
) {
safeLog(`Locking issue ${hydrated.number}`);
await issue.lockIssue();
} else {
if (hydrated.locked) {
safeLog(`Issue ${hydrated.number} is already locked. Ignoring`);
} else if (hydrated.open) {
safeLog(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}),
)
}
}
}
-33
View File
@@ -1,33 +0,0 @@
name: Locker
description: Lock closed issues and PRs after some time has passed
inputs:
token:
description: GitHub token with issue, comment, and label read/write permissions
default: ${{ github.token }}
daysSinceClose:
description: Days to wait since closing before locking the item
required: true
daysSinceUpdate:
description: days to wait since the last interaction before locking the item
required: true
milestoneName:
description: items with these milestones will be considered (name only, must match ID)
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will not be considered. May be "*".
ignoreMilestoneNames:
description: items with these milestones will not be considered (names only, must match IDs). May be "*".
ignoreMilestoneIds:
description: items with these milestones will not be considered (IDs only, must match names)
ignoreLabels:
description: items with these labels will not be considered
minimumVotes:
descriptions: Only issues with at least this many votes will be considered.
maximumVotes:
descriptions: Only issues fewer or equal to this many votes will be considered.
readonly:
description: If true, changes are not applied.
runs:
using: 'node12'
main: 'index.js'
-20
View File
@@ -1,20 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../common/utils");
const Locker_1 = require("./Locker");
const Action_1 = require("../common/Action");
class LockerAction extends Action_1.Action {
constructor() {
super(...arguments);
this.id = 'Locker';
}
async onTriggered(github) {
await new Locker_1.Locker(github, +(0, utils_1.getRequiredInput)('daysSinceClose'), +(0, utils_1.getRequiredInput)('daysSinceUpdate'), (0, utils_1.getInput)('labels') || undefined, (0, utils_1.getInput)('milestoneName') || undefined, (0, utils_1.getInput)('milestoneId') || undefined, (0, utils_1.getInput)('ignoreLabels') || undefined, (0, utils_1.getInput)('ignoreMilestoneNames') || undefined, (0, utils_1.getInput)('ignoreMilestoneIds') || undefined, +((0, utils_1.getInput)('minimumVotes') || 0), +((0, utils_1.getInput)('maximumVotes') || 9999999)).run();
}
}
new LockerAction().run(); // eslint-disable-line
//# sourceMappingURL=index.js.map
-31
View File
@@ -1,31 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { OctoKit } from '../api/octokit';
import { getInput, getRequiredInput } from '../common/utils';
import { Locker } from './Locker';
import { Action } from '../common/Action';
class LockerAction extends Action {
id = 'Locker';
async onTriggered(github: OctoKit) {
await new Locker(
github,
+getRequiredInput('daysSinceClose'),
+getRequiredInput('daysSinceUpdate'),
getInput('labels') || undefined,
getInput('milestoneName') || undefined,
getInput('milestoneId') || undefined,
getInput('ignoreLabels') || undefined,
getInput('ignoreMilestoneNames') || undefined,
getInput('ignoreMilestoneIds') || undefined,
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999)
).run();
}
}
new LockerAction().run(); // eslint-disable-line
-73
View File
@@ -1,73 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Reopener = void 0;
const utils_1 = require("../common/utils");
const ActionBase_1 = require("../common/ActionBase");
class Reopener extends ActionBase_1.ActionBase {
constructor(github, alsoApplyToOpenIssues, addLabels, removeLabels, reopenComment, setMilestoneId, labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes) {
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes);
this.github = github;
this.alsoApplyToOpenIssues = alsoApplyToOpenIssues;
this.addLabels = addLabels;
this.removeLabels = removeLabels;
this.reopenComment = reopenComment;
this.setMilestoneId = setMilestoneId;
}
async run() {
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
(0, utils_1.safeLog)(`alsoApplyToOpenIssues: ${this.alsoApplyToOpenIssues}`);
const query = this.buildQuery((this.alsoApplyToOpenIssues ? "" : "is:closed ") + "is:unlocked");
for await (const page of this.github.query({ q: query })) {
await Promise.all(page.map(async (issue) => {
const hydrated = await issue.getIssue();
if (!hydrated.locked && (this.alsoApplyToOpenIssues || hydrated.open === false) && this.validateIssue(hydrated)
// TODO: Verify closed and updated timestamps
) {
if (hydrated.open === false) {
(0, utils_1.safeLog)(`Reopening issue ${hydrated.number}`);
await issue.reopenIssue();
}
if (this.setMilestoneId != undefined) {
(0, utils_1.safeLog)(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
if (removeLabelsSet.length > 0) {
for (const removeLabel of removeLabelsSet) {
if (removeLabel && removeLabel.length > 0) {
(0, utils_1.safeLog)(`Removing label on issue ${hydrated.number}: ${removeLabel}`);
await issue.removeLabel(removeLabel);
}
}
}
if (addLabelsSet.length > 0) {
for (const addLabel of addLabelsSet) {
if (addLabel && addLabel.length > 0) {
(0, utils_1.safeLog)(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
if (this.reopenComment) {
(0, utils_1.safeLog)(`Posting comment to issue ${hydrated.number}.`);
await issue.postComment(this.reopenComment);
}
}
else {
if (hydrated.locked) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is locked. Ignoring`);
}
else if (!this.alsoApplyToOpenIssues && hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}));
}
}
}
exports.Reopener = Reopener;
//# sourceMappingURL=Reopener.js.map
-85
View File
@@ -1,85 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GitHub, Issue } from '../api/api';
import { daysAgoToHumanReadbleDate, safeLog } from '../common/utils';
import { ActionBase } from '../common/ActionBase';
export class Reopener extends ActionBase {
constructor(
private github: GitHub,
private alsoApplyToOpenIssues: boolean,
private addLabels?: string,
private removeLabels?: string,
private reopenComment?: string,
private setMilestoneId?: string,
labels?: string,
milestoneName?: string,
milestoneId?: string,
ignoreLabels?: string,
ignoreMilestoneNames?: string,
ignoreMilestoneIds?: string,
minimumVotes?: number,
maximumVotes?: number
)
{
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes);
}
async run() {
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
safeLog(`alsoApplyToOpenIssues: ${this.alsoApplyToOpenIssues}`);
const query = this.buildQuery((this.alsoApplyToOpenIssues ? "": "is:closed ") + "is:unlocked");
for await (const page of this.github.query({ q: query })) {
await Promise.all(
page.map(async (issue) => {
const hydrated = await issue.getIssue();
if (!hydrated.locked && (this.alsoApplyToOpenIssues || hydrated.open === false) && this.validateIssue(hydrated)
// TODO: Verify closed and updated timestamps
) {
if (hydrated.open === false) {
safeLog(`Reopening issue ${hydrated.number}`);
await issue.reopenIssue();
}
if (this.setMilestoneId != undefined) {
safeLog(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
if (removeLabelsSet.length > 0) {
for (const removeLabel of removeLabelsSet) {
if (removeLabel && removeLabel.length > 0) {
safeLog(`Removing label on issue ${hydrated.number}: ${removeLabel}`);
await issue.removeLabel(removeLabel);
}
}
}
if (addLabelsSet.length > 0) {
for (const addLabel of addLabelsSet) {
if (addLabel && addLabel.length > 0) {
safeLog(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
if (this.reopenComment) {
safeLog(`Posting comment to issue ${hydrated.number}.`);
await issue.postComment(this.reopenComment);
}
} else {
if (hydrated.locked) {
safeLog(`Issue ${hydrated.number} is locked. Ignoring`);
} else if (!this.alsoApplyToOpenIssues && hydrated.open) {
safeLog(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}),
)
}
}
}
-37
View File
@@ -1,37 +0,0 @@
name: Locker
description: Lock closed issues and PRs after some time has passed
inputs:
token:
description: GitHub token with issue, comment, and label read/write permissions
default: ${{ github.token }}
alsoApplyToOpenIssues:
description: If true, applies to issues that are already opened (to add/remove labels, etc., but not reopen).
addLabels:
description: Labels to add to issue as it is reopend.
reopenComment:
description: Comment to add upon reopening the issue.
setMilestoneId:
description: Milestone to set reopened issue to.
removeLabels:
description: Labels to remove from issue as it is reopened.
milestoneName:
description: items with these milestones will be considered (name only, must match ID)
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will not be considered. May be "*".
ignoreMilestoneNames:
description: items with these milestones will not be considered (names only, must match IDs). May be "*".
ignoreMilestoneIds:
description: items with these milestones will not be considered (IDs only, must match names)
ignoreLabels:
description: items with these labels will not be considered
minimumVotes:
descriptions: Only issues with at least this many votes will be considered.
maximumVotes:
descriptions: Only issues fewer or equal to this many votes will be considered.
readonly:
description: If true, changes are not applied.
runs:
using: 'node12'
main: 'index.js'
-21
View File
@@ -1,21 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../common/utils");
const Reopener_1 = require("./Reopener");
const Action_1 = require("../common/Action");
class ReopenerAction extends Action_1.Action {
constructor() {
super(...arguments);
this.id = 'Reopener';
}
async onTriggered(github) {
const alsoApplyToOpenIssues = (0, utils_1.getInput)('alsoApplyToOpenIssues');
await new Reopener_1.Reopener(github, alsoApplyToOpenIssues != undefined && alsoApplyToOpenIssues.toLowerCase() == 'true', (0, utils_1.getInput)('addLabels') || undefined, (0, utils_1.getInput)('removeLabels') || undefined, (0, utils_1.getInput)('reopenComment') || '', (0, utils_1.getInput)('setMilestoneId') || undefined, (0, utils_1.getInput)('labels') || undefined, (0, utils_1.getInput)('milestoneName') || undefined, (0, utils_1.getInput)('milestoneId') || undefined, (0, utils_1.getInput)('ignoreLabels') || undefined, (0, utils_1.getInput)('ignoreMilestoneNames') || undefined, (0, utils_1.getInput)('ignoreMilestoneIds') || undefined, +((0, utils_1.getInput)('minimumVotes') || 0), +((0, utils_1.getInput)('maximumVotes') || 9999999)).run();
}
}
new ReopenerAction().run(); // eslint-disable-line
//# sourceMappingURL=index.js.map
-35
View File
@@ -1,35 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { OctoKit } from '../api/octokit';
import { getInput, getRequiredInput } from '../common/utils';
import { Reopener } from './Reopener';
import { Action } from '../common/Action';
class ReopenerAction extends Action {
id = 'Reopener';
async onTriggered(github: OctoKit) {
const alsoApplyToOpenIssues: string | undefined = getInput('alsoApplyToOpenIssues');
await new Reopener(
github,
alsoApplyToOpenIssues != undefined && alsoApplyToOpenIssues.toLowerCase() == 'true',
getInput('addLabels') || undefined,
getInput('removeLabels') || undefined,
getInput('reopenComment') || '',
getInput('setMilestoneId') || undefined,
getInput('labels') || undefined,
getInput('milestoneName') || undefined,
getInput('milestoneId') || undefined,
getInput('ignoreLabels') || undefined,
getInput('ignoreMilestoneNames') || undefined,
getInput('ignoreMilestoneIds') || undefined,
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999)
).run();
}
}
new ReopenerAction().run(); // eslint-disable-line
-106
View File
@@ -1,106 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.StaleCloser = void 0;
const ActionBase_1 = require("../common/ActionBase");
const utils_1 = require("../common/utils");
class StaleCloser extends ActionBase_1.ActionBase {
constructor(github, closeDays, labels, closeComment, pingDays, pingComment, additionalTeam, addLabels, removeLabels, setMilestoneId, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes, involves) {
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes, involves);
this.github = github;
this.closeDays = closeDays;
this.closeComment = closeComment;
this.pingDays = pingDays;
this.pingComment = pingComment;
this.additionalTeam = additionalTeam;
this.addLabels = addLabels;
this.removeLabels = removeLabels;
this.setMilestoneId = setMilestoneId;
}
async run() {
const updatedTimestamp = (0, utils_1.daysAgoToHumanReadbleDate)(this.closeDays);
const pingTimestamp = this.pingDays ? (0, utils_1.daysAgoToTimestamp)(this.pingDays) : undefined;
const query = this.buildQuery((this.closeDays ? `updated:<${updatedTimestamp} ` : "") + "is:open is:unlocked");
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
for await (const page of this.github.query({ q: query })) {
for (const issue of page) {
const hydrated = await issue.getIssue();
const lastCommentIterator = await issue.getComments(true).next();
if (lastCommentIterator.done) {
throw Error('Unexpected comment data');
}
const lastComment = lastCommentIterator.value[0];
if (hydrated.open && this.validateIssue(hydrated)
// TODO: Verify updated timestamp
) {
if (!lastComment ||
lastComment.author.isGitHubApp ||
pingTimestamp == undefined ||
// TODO: List the collaborators once per go rather than checking a single user each issue
this.additionalTeam.includes(lastComment.author.name) ||
await issue.hasWriteAccess(lastComment.author)) {
if (pingTimestamp != undefined) {
if (lastComment) {
(0, utils_1.safeLog)(`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Closing.`);
}
else {
(0, utils_1.safeLog)(`No comments on issue ${hydrated.number}. Closing.`);
}
}
if (this.closeComment) {
(0, utils_1.safeLog)(`Posting comment on issue ${hydrated.number}`);
await issue.postComment(this.closeComment);
}
if (removeLabelsSet.length > 0) {
for (const removeLabel of removeLabelsSet) {
if (removeLabel && removeLabel.length > 0) {
(0, utils_1.safeLog)(`Removing label on issue ${hydrated.number}: ${removeLabel}`);
await issue.removeLabel(removeLabel);
}
}
}
if (addLabelsSet.length > 0) {
for (const addLabel of addLabelsSet) {
if (addLabel && addLabel.length > 0) {
(0, utils_1.safeLog)(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
await issue.closeIssue("not_planned");
if (this.setMilestoneId != undefined) {
(0, utils_1.safeLog)(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
(0, utils_1.safeLog)(`Closing issue ${hydrated.number}.`);
}
else {
// Ping
if (hydrated.updatedAt < pingTimestamp && hydrated.assignee) {
(0, utils_1.safeLog)(`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Pinging @${hydrated.assignee}`);
if (this.pingComment) {
await issue.postComment(this.pingComment
.replace('${assignee}', hydrated.assignee)
.replace('${author}', hydrated.author.name));
}
}
else {
(0, utils_1.safeLog)(`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Skipping.${hydrated.assignee ? ' cc @' + hydrated.assignee : ''}`);
}
}
}
else {
if (!hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is not open. Ignoring`);
}
}
}
}
}
}
exports.StaleCloser = StaleCloser;
//# sourceMappingURL=StaleCloser.js.map
-128
View File
@@ -1,128 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GitHub } from '../api/api';
import { ActionBase } from '../common/ActionBase';
import { daysAgoToHumanReadbleDate, daysAgoToTimestamp, safeLog } from '../common/utils';
export class StaleCloser extends ActionBase {
constructor(
private github: GitHub,
private closeDays: number,
labels: string,
private closeComment: string,
private pingDays: number,
private pingComment: string,
private additionalTeam: string[],
private addLabels?: string,
private removeLabels?: string,
private setMilestoneId?: string,
milestoneName?: string,
milestoneId?: string,
ignoreLabels?: string,
ignoreMilestoneNames?: string,
ignoreMilestoneIds?: string,
minimumVotes?: number,
maximumVotes?: number,
involves?: string
)
{
super(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes, involves);
}
async run() {
const updatedTimestamp = daysAgoToHumanReadbleDate(this.closeDays);
const pingTimestamp = this.pingDays ? daysAgoToTimestamp(this.pingDays) : undefined;
const query = this.buildQuery((this.closeDays ? `updated:<${updatedTimestamp} ` : "") + "is:open is:unlocked");
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
for await (const page of this.github.query({ q: query })) {
for (const issue of page) {
const hydrated = await issue.getIssue();
const lastCommentIterator = await issue.getComments(true).next();
if (lastCommentIterator.done) {
throw Error('Unexpected comment data');
}
const lastComment = lastCommentIterator.value[0];
if (hydrated.open && this.validateIssue(hydrated)
// TODO: Verify updated timestamp
) {
if (
!lastComment ||
lastComment.author.isGitHubApp ||
pingTimestamp == undefined ||
// TODO: List the collaborators once per go rather than checking a single user each issue
this.additionalTeam.includes(lastComment.author.name) ||
await issue.hasWriteAccess(lastComment.author)
) {
if (pingTimestamp != undefined) {
if (lastComment) {
safeLog(
`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Closing.`,
);
} else {
safeLog(`No comments on issue ${hydrated.number}. Closing.`);
}
}
if (this.closeComment) {
safeLog(`Posting comment on issue ${hydrated.number}`);
await issue.postComment(this.closeComment);
}
if (removeLabelsSet.length > 0) {
for (const removeLabel of removeLabelsSet) {
if (removeLabel && removeLabel.length > 0) {
safeLog(`Removing label on issue ${hydrated.number}: ${removeLabel}`);
await issue.removeLabel(removeLabel);
}
}
}
if (addLabelsSet.length > 0) {
for (const addLabel of addLabelsSet) {
if (addLabel && addLabel.length > 0) {
safeLog(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
await issue.closeIssue("not_planned");
if (this.setMilestoneId != undefined) {
safeLog(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
safeLog(`Closing issue ${hydrated.number}.`);
} else {
// Ping
if (hydrated.updatedAt < pingTimestamp && hydrated.assignee) {
safeLog(
`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Pinging @${hydrated.assignee}`,
);
if (this.pingComment) {
await issue.postComment(
this.pingComment
.replace('${assignee}', hydrated.assignee)
.replace('${author}', hydrated.author.name),
);
}
} else {
safeLog(
`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Skipping.${
hydrated.assignee ? ' cc @' + hydrated.assignee : ''
}`,
);
}
}
} else {
if (!hydrated.open) {
safeLog(`Issue ${hydrated.number} is not open. Ignoring`);
}
}
}
}
}
}
-47
View File
@@ -1,47 +0,0 @@
name: Stale Issue Closer
description: Close issues that are marked with a specified label and were last interacted with by a contributor or bot
inputs:
token:
description: GitHub token with issue, comment, and label read/write permissions
default: ${{ github.token }}
closeDays:
description: Days to wait before closing the issue
required: true
closeComment:
description: Comment to add upon closing the issue
pingDays:
description: Days to wait before pinging the assignee, if any. If set, issue is not closed if there is an assignee.
additionalTeam:
description: Pipe-separated list of additional users to treat as team members
pingComment:
description: Comment to add when pinging assignee. ${assignee} and ${author} are replaced.
milestoneName:
description: items with these milestones will be considered (name only, must match ID)
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will not be considered. May be "*".
required: true
ignoreMilestoneNames:
description: items with these milestones will not be considered (names only, must match IDs). May be "*".
ignoreMilestoneIds:
description: items with these milestones will not be considered (IDs only, must match names)
ignoreLabels:
description: items with these labels will not be considered
addLabels:
description: Labels to add to issue as it is closed.
removeLabels:
description: Labels to remove from issue as it is closed.
setMilestoneId:
description: Milestone to set closed issue to.
minimumVotes:
descriptions: Only issues with at least this many votes will be considered.
maximumVotes:
descriptions: Only issues fewer or equal to this many votes will be considered.
involves:
descriptions: Qualifier to find issues that in some way involve a certain user either as an author, assignee, or mentions.
readonly:
description: If true, changes are not applied.
runs:
using: 'node12'
main: 'index.js'
-21
View File
@@ -1,21 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../common/utils");
const StaleCloser_1 = require("./StaleCloser");
const Action_1 = require("../common/Action");
class StaleCloserAction extends Action_1.Action {
constructor() {
super(...arguments);
this.id = 'StaleCloser';
}
async onTriggered(github) {
var _a;
await new StaleCloser_1.StaleCloser(github, +(0, utils_1.getRequiredInput)('closeDays'), (0, utils_1.getRequiredInput)('labels'), (0, utils_1.getInput)('closeComment') || '', +((0, utils_1.getInput)('pingDays') || 0), (0, utils_1.getInput)('pingComment') || '', ((_a = (0, utils_1.getInput)('additionalTeam')) !== null && _a !== void 0 ? _a : '').split(','), (0, utils_1.getInput)('addLabels') || undefined, (0, utils_1.getInput)('removeLabels') || undefined, (0, utils_1.getInput)('setMilestoneId') || undefined, (0, utils_1.getInput)('milestoneName') || undefined, (0, utils_1.getInput)('milestoneId') || undefined, (0, utils_1.getInput)('ignoreLabels') || undefined, (0, utils_1.getInput)('ignoreMilestoneNames') || undefined, (0, utils_1.getInput)('ignoreMilestoneIds') || undefined, +((0, utils_1.getInput)('minimumVotes') || 0), +((0, utils_1.getInput)('maximumVotes') || 9999999), (0, utils_1.getInput)('involves') || undefined).run();
}
}
new StaleCloserAction().run(); // eslint-disable-line
//# sourceMappingURL=index.js.map
-38
View File
@@ -1,38 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { OctoKit } from '../api/octokit'
import { getInput, getRequiredInput } from '../common/utils'
import { StaleCloser } from './StaleCloser'
import { Action } from '../common/Action'
class StaleCloserAction extends Action {
id = 'StaleCloser';
async onTriggered(github: OctoKit) {
await new StaleCloser(
github,
+getRequiredInput('closeDays'),
getRequiredInput('labels'),
getInput('closeComment') || '',
+(getInput('pingDays') || 0),
getInput('pingComment') || '',
(getInput('additionalTeam') ?? '').split(','),
getInput('addLabels') || undefined,
getInput('removeLabels') || undefined,
getInput('setMilestoneId') || undefined,
getInput('milestoneName') || undefined,
getInput('milestoneId') || undefined,
getInput('ignoreLabels') || undefined,
getInput('ignoreMilestoneNames') || undefined,
getInput('ignoreMilestoneIds') || undefined,
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999),
getInput('involves') || undefined
).run();
}
}
new StaleCloserAction().run(); // eslint-disable-line
-7
View File
@@ -1,7 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=api.js.map
-123
View File
@@ -1,123 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface GitHub {
repoOwner: string;
repoName: string;
query(query: Query): AsyncIterableIterator<GitHubIssue[]>;
hasWriteAccess(user: User): Promise<boolean>;
repoHasLabel(label: string): Promise<boolean>;
createLabel(label: string, color: string, description: string): Promise<void>;
deleteLabel(label: string): Promise<void>;
readConfig(path: string): Promise<any>;
dispatch(title: string): Promise<void>;
createIssue(owner: string, repo: string, title: string, body: string): Promise<void>;
releaseContainsCommit(release: string, commit: string): Promise<'yes' | 'no' | 'unknown'>;
/**
* Returns what we think the current milestone for the repo is based on the due on date.
* @returns The milestone id if one is found, else undefined
*/
getCurrentRepoMilestone(): Promise<number | undefined>;
}
export interface GitHubIssue extends GitHub {
getIssue(): Promise<Issue>;
postComment(body: string): Promise<void>;
deleteComment(id: number): Promise<void>;
getComments(last?: boolean): AsyncIterableIterator<Comment[]>;
closeIssue(reason: 'completed' | 'not_planned'): Promise<void>;
lockIssue(): Promise<void>;
unlockIssue(): Promise<void>;
reopenIssue(): Promise<void>;
setMilestone(milestoneId: number): Promise<void>;
addLabel(label: string): Promise<void>;
removeLabel(label: string): Promise<void>;
addAssignee(assignee: string): Promise<void>;
removeAssignee(assignee: string): Promise<void>;
getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined>;
}
type SortVar =
| 'comments'
| 'reactions'
| 'reactions-+1'
| 'reactions--1'
| 'reactions-smile'
| 'reactions-thinking_face'
| 'reactions-heart'
| 'reactions-tada'
| 'interactions'
| 'created'
| 'updated';
type SortOrder = 'asc' | 'desc';
export type Reactions = {
'+1': number;
'-1': number;
laugh: number;
hooray: number;
confused: number;
heart: number;
rocket: number;
eyes: number;
};
export interface User {
name: string;
isGitHubApp?: boolean;
}
export interface Comment {
author: User;
body: string;
id: number;
timestamp: number;
}
export interface Issue {
author: User;
body: string;
title: string;
labels: string[];
open: boolean;
locked: boolean;
number: number;
isPr: boolean;
numComments: number;
reactions: Reactions;
milestone: Milestone | null;
assignee?: string;
assignees: string[];
createdAt: number;
updatedAt: number;
closedAt?: number;
}
export interface Milestone {
milestoneId: number;
title: string;
description: string;
numClosedIssues: number;
numOpenIssues: number;
dueOn: Date | null;
createdAt: Date | null;
closedAt: Date | null;
state: 'open' | 'closed';
}
export interface Query {
q: string;
sort?: SortVar;
order?: SortOrder;
}
-484
View File
@@ -1,484 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.OctoKitIssue = exports.OctoKit = exports.getNumRequests = void 0;
const github_1 = require("@actions/github");
const child_process_1 = require("child_process");
const utils_1 = require("../common/utils");
let numRequests = 0;
const getNumRequests = () => numRequests;
exports.getNumRequests = getNumRequests;
class OctoKit {
constructor(token, params, options = { readonly: false }) {
this.token = token;
this.params = params;
this.options = options;
// when in readonly mode, record labels just-created so at to not throw unneccesary errors
this.mockLabels = new Set();
this.writeAccessCache = {};
this._octokit = (0, github_1.getOctokit)(token);
this.repoName = params.repo;
this.repoOwner = params.owner;
}
get octokit() {
numRequests++;
return this._octokit;
}
getIssueByNumber(number) {
return new OctoKitIssue(this.token, this.params, { number: number });
}
// TODO: just iterate over the issues in a page here instead of making caller do it
async *query(query) {
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`;
const options = {
...query,
q,
per_page: 100,
headers: { Accept: 'application/vnd.github.squirrel-girl-preview+json' },
};
let pageNum = 0;
const timeout = async () => {
if (pageNum < 2) {
/* pass */
}
else if (pageNum < 4) {
await new Promise((resolve) => setTimeout(resolve, 10000));
}
else {
await new Promise((resolve) => setTimeout(resolve, 30000));
}
};
for await (const pageResponse of this.octokit.paginate.iterator(this.octokit.rest.search.issuesAndPullRequests, options)) {
await timeout();
numRequests++;
const page = pageResponse.data;
(0, utils_1.safeLog)(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`);
yield page.map((issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue), this.options));
}
}
async createIssue(owner, repo, title, body) {
(0, utils_1.safeLog)(`Creating issue \`${title}\` on ${owner}/${repo}`);
if (!this.options.readonly)
await this.octokit.rest.issues.create({ owner, repo, title, body });
}
octokitIssueToIssue(issue) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
return {
author: { name: (_b = (_a = issue.user) === null || _a === void 0 ? void 0 : _a.login) !== null && _b !== void 0 ? _b : 'unkown', isGitHubApp: ((_c = issue.user) === null || _c === void 0 ? void 0 : _c.type) === 'Bot' },
body: (_d = issue.body) !== null && _d !== void 0 ? _d : '',
number: issue.number,
title: issue.title,
isPr: !!((_e = issue.pull_request) === null || _e === void 0 ? void 0 : _e.html_url),
labels: issue.labels.map((label) => { var _a; return (typeof label === 'string' ? label : (_a = label.name) !== null && _a !== void 0 ? _a : ''); }),
open: issue.state === 'open',
locked: issue.locked,
numComments: issue.comments,
reactions: issue.reactions,
assignee: (_g = (_f = issue.assignee) === null || _f === void 0 ? void 0 : _f.login) !== null && _g !== void 0 ? _g : (_j = (_h = issue.assignees) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.login,
assignees: (_l = (_k = issue.assignees) === null || _k === void 0 ? void 0 : _k.map((assignee) => assignee.login)) !== null && _l !== void 0 ? _l : [],
milestone: issue.milestone ? this.octokitMilestoneToMilestone(issue.milestone) : null,
createdAt: +new Date(issue.created_at),
updatedAt: +new Date(issue.updated_at),
closedAt: issue.closed_at ? +new Date(issue.closed_at) : undefined,
};
}
octokitMilestoneToMilestone(milestone) {
var _a;
if ((milestone === null || milestone === void 0 ? void 0 : milestone.number) === undefined) {
return null;
}
return {
title: milestone.title,
milestoneId: milestone.number,
// Remove the time portions of the dates as they're not important
createdAt: milestone.created_at !== null ? new Date(milestone.created_at.split('T')[0]) : null,
dueOn: milestone.due_on !== null ? new Date(milestone.due_on.split('T')[0]) : null,
closedAt: milestone.closed_at !== null ? new Date(milestone.closed_at.split('T')[0]) : null,
description: (_a = milestone.description) !== null && _a !== void 0 ? _a : '',
numClosedIssues: milestone.closed_issues,
numOpenIssues: milestone.open_issues,
state: milestone.state === 'open' ? 'open' : 'closed',
};
}
async hasWriteAccess(user) {
if (user.name in this.writeAccessCache) {
(0, utils_1.safeLog)('Got permissions from cache for ' + user);
return this.writeAccessCache[user.name];
}
(0, utils_1.safeLog)('Fetching permissions for ' + user.name);
const permissions = (await this.octokit.rest.repos.getCollaboratorPermissionLevel({
...this.params,
username: user.name,
})).data.permission;
return (this.writeAccessCache[user.name] = permissions === 'admin' || permissions === 'write');
}
async repoHasLabel(name) {
try {
await this.octokit.rest.issues.getLabel({ ...this.params, name });
return true;
}
catch (err) {
const statusErorr = err;
if (statusErorr.status === 404) {
return this.options.readonly && this.mockLabels.has(name);
}
throw err;
}
}
async createLabel(name, color, description) {
(0, utils_1.safeLog)('Creating label ' + name);
if (!this.options.readonly)
await this.octokit.rest.issues.createLabel({ ...this.params, color, description, name });
else
this.mockLabels.add(name);
}
async deleteLabel(name) {
(0, utils_1.safeLog)('Deleting label ' + name);
try {
if (!this.options.readonly)
await this.octokit.rest.issues.deleteLabel({ ...this.params, name });
}
catch (err) {
const statusErorr = err;
if (statusErorr.status === 404) {
return;
}
throw err;
}
}
async readConfig(path) {
(0, utils_1.safeLog)('Reading config at ' + path);
const repoPath = `.github/${path}.json`;
try {
const data = (await this.octokit.rest.repos.getContent({ ...this.params, path: repoPath })).data;
if ('type' in data && data.type === 'file' && 'content' in data) {
if (data.encoding === 'base64' && data.content) {
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'));
}
throw Error(`Could not read contents "${data.content}" in encoding "${data.encoding}"`);
}
throw Error('Found directory at config path when expecting file' + JSON.stringify(data));
}
catch (e) {
throw Error('Error with config file at ' + repoPath + ': ' + JSON.stringify(e));
}
}
async releaseContainsCommit(release, commit) {
const isHash = (s) => /^[a-fA-F0-9]*$/.test(s);
if (!isHash(release) || !isHash(commit))
return 'unknown';
return new Promise((resolve, reject) => (0, child_process_1.exec)(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => {
if (!err || err.code === 1) {
resolve(!err ? 'yes' : 'no');
}
else if (err.message.includes(`Not a valid commit name ${release}`)) {
// release branch is forked. Probably in endgame. Not released.
resolve('no');
}
else if (err.message.includes(`Not a valid commit name ${commit}`)) {
// commit is probably in a different repo.
resolve('unknown');
}
else {
reject(err);
}
}));
}
async getCurrentRepoMilestone() {
(0, utils_1.safeLog)(`Getting repo milestone for ${this.params.owner}/${this.params.repo}`);
// Fetch all milestones open for this repo
const allMilestones = (await this.octokit.rest.issues.listMilestones({
owner: this.params.owner,
repo: this.params.repo,
state: 'open',
sort: 'due_on',
direction: 'asc',
})).data;
const currentDate = new Date();
const possibleMilestones = allMilestones
.filter((milestone) => new Date(milestone.due_on === null ? currentDate : milestone.due_on) > currentDate &&
currentDate > new Date(milestone.created_at) &&
!milestone.title.includes('Recovery'))
.sort((a, b) => { var _a, _b; return +new Date((_a = a.due_on) !== null && _a !== void 0 ? _a : currentDate) - +new Date((_b = b.due_on) !== null && _b !== void 0 ? _b : currentDate); });
if (possibleMilestones.length === 0) {
return undefined;
}
return possibleMilestones[0].number;
}
async dispatch(title) {
(0, utils_1.safeLog)('Dispatching ' + title);
if (!this.options.readonly)
await this.octokit.rest.repos.createDispatchEvent({ ...this.params, event_type: title });
}
}
exports.OctoKit = OctoKit;
class OctoKitIssue extends OctoKit {
constructor(token, params, issueData, options = { readonly: false }) {
super(token, params, options);
this.params = params;
this.issueData = issueData;
(0, utils_1.safeLog)('running bot on issue', issueData.number);
}
async addAssignee(assignee) {
(0, utils_1.safeLog)('Adding assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.addAssignees({
...this.params,
issue_number: this.issueData.number,
assignees: [assignee],
});
}
}
async removeAssignee(assignee) {
(0, utils_1.safeLog)('Removing assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.removeAssignees({
...this.params,
issue_number: this.issueData.number,
assignees: [assignee],
});
}
}
async closeIssue(reason) {
(0, utils_1.safeLog)('Closing issue ' + this.issueData.number);
if (!this.options.readonly) {
const issue = await this.octokit.rest.issues.get({
...this.params,
issue_number: this.issueData.number,
});
// Don't close already closed issues even if it means changing the state
if (issue.data.state === 'closed') {
return;
}
await this.octokit.rest.issues
.update({
...this.params,
issue_number: this.issueData.number,
state: 'closed',
state_reason: reason,
})
.catch((e) => {
(0, utils_1.safeLog)('error closing issue:', e);
});
}
}
async reopenIssue() {
(0, utils_1.safeLog)('Reopening issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
...this.params,
issue_number: this.issueData.number,
state: 'open',
});
}
async lockIssue() {
(0, utils_1.safeLog)('Locking issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.lock({ ...this.params, issue_number: this.issueData.number });
}
async unlockIssue() {
(0, utils_1.safeLog)('Unlocking issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.unlock({ ...this.params, issue_number: this.issueData.number });
}
async getIssue() {
if (isIssue(this.issueData)) {
(0, utils_1.safeLog)('Got issue data from query result ' + this.issueData.number);
return this.issueData;
}
(0, utils_1.safeLog)('Fetching issue ' + this.issueData.number);
const issue = (await this.octokit.rest.issues.get({
...this.params,
issue_number: this.issueData.number,
mediaType: { previews: ['squirrel-girl'] },
})).data;
return (this.issueData = this.octokitIssueToIssue(issue));
}
async postComment(body) {
(0, utils_1.safeLog)(`Posting comment on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.createComment({
...this.params,
issue_number: this.issueData.number,
body,
});
}
async deleteComment(id) {
(0, utils_1.safeLog)(`Deleting comment ${id} on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.deleteComment({
owner: this.params.owner,
repo: this.params.repo,
comment_id: id,
});
}
async setMilestone(milestoneId) {
(0, utils_1.safeLog)(`Setting milestone for ${this.issueData.number} to ${milestoneId}`);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
...this.params,
issue_number: this.issueData.number,
milestone: milestoneId,
});
}
async *getComments(last) {
(0, utils_1.safeLog)('Fetching comments for ' + this.issueData.number);
const response = this.octokit.paginate.iterator(this.octokit.rest.issues.listComments, {
...this.params,
issue_number: this.issueData.number,
per_page: 100,
...(last ? { per_page: 1, page: (await this.getIssue()).numComments } : {}),
});
for await (const page of response) {
numRequests++;
yield page.data.map((comment) => {
var _a, _b, _c, _d;
return ({
author: { name: (_b = (_a = comment.user) === null || _a === void 0 ? void 0 : _a.login) !== null && _b !== void 0 ? _b : '', isGitHubApp: ((_c = comment.user) === null || _c === void 0 ? void 0 : _c.type) === 'Bot' },
body: (_d = comment.body) !== null && _d !== void 0 ? _d : '',
id: comment.id,
timestamp: +new Date(comment.created_at),
});
});
}
}
async addLabel(name) {
(0, utils_1.safeLog)(`Adding label ${name} to ${this.issueData.number}`);
if (!(await this.repoHasLabel(name))) {
throw Error(`Action could not execute becuase label ${name} is not defined.`);
}
if (!this.options.readonly)
await this.octokit.rest.issues.addLabels({
...this.params,
issue_number: this.issueData.number,
labels: [name],
});
}
async getAssigner(assignee) {
var _a, _b;
const options = {
...this.params,
issue_number: this.issueData.number,
};
let assigner;
for await (const event of this.octokit.paginate.iterator(this.octokit.rest.issues.listEventsForTimeline, options)) {
numRequests++;
const timelineEvents = event.data;
for (const timelineEvent of timelineEvents) {
if (timelineEvent.event === 'assigned' && ((_a = timelineEvent.assignee) === null || _a === void 0 ? void 0 : _a.login) === assignee) {
assigner = (_b = timelineEvent.actor) === null || _b === void 0 ? void 0 : _b.login;
}
}
if (assigner) {
break;
}
}
if (!assigner) {
throw Error('Expected to find ' + assignee + ' in issue timeline but did not.');
}
return assigner;
}
async removeLabel(name) {
(0, utils_1.safeLog)(`Removing label ${name} from ${this.issueData.number}`);
try {
if (!this.options.readonly)
await this.octokit.rest.issues.removeLabel({
...this.params,
issue_number: this.issueData.number,
name,
});
}
catch (err) {
const statusErorr = err;
if (statusErorr.status === 404) {
(0, utils_1.safeLog)(`Label ${name} not found on issue`);
return;
}
throw err;
}
}
async getClosingInfo(alreadyChecked = []) {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (alreadyChecked.includes(this.issueData.number)) {
return undefined;
}
alreadyChecked.push(this.issueData.number);
if ((await this.getIssue()).open) {
return;
}
const closingHashComment = /(?:\\|\/)closedWith (?:https:\/\/github\.com\/microsoft\/vscode\/commit\/)?([a-fA-F0-9]{7,40})/;
const options = {
...this.params,
issue_number: this.issueData.number,
};
let closingCommit;
const crossReferencing = [];
for await (const event of this.octokit.paginate.iterator(this.octokit.rest.issues.listEventsForTimeline, options)) {
numRequests++;
const timelineEvents = event.data;
for (const timelineEvent of timelineEvents) {
if ((timelineEvent.event === 'closed' || timelineEvent.event === 'merged') &&
timelineEvent.created_at &&
timelineEvent.commit_id &&
((_a = timelineEvent.commit_url) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(`/${this.params.owner}/${this.params.repo}/`.toLowerCase()))) {
closingCommit = {
hash: timelineEvent.commit_id,
timestamp: +new Date(timelineEvent.created_at),
};
}
if (timelineEvent.event === 'reopened') {
closingCommit = undefined;
}
if (timelineEvent.created_at &&
timelineEvent.event === 'commented' &&
!((_b = timelineEvent.body) === null || _b === void 0 ? void 0 : _b.includes('UNABLE_TO_LOCATE_COMMIT_MESSAGE')) &&
closingHashComment.test(timelineEvent.body)) {
closingCommit = {
hash: closingHashComment.exec(timelineEvent.body)[1],
timestamp: +new Date(timelineEvent.created_at),
};
}
if (timelineEvent.event === 'cross-referenced' &&
((_d = (_c = timelineEvent.source) === null || _c === void 0 ? void 0 : _c.issue) === null || _d === void 0 ? void 0 : _d.number) &&
((_g = (_f = (_e = timelineEvent.source) === null || _e === void 0 ? void 0 : _e.issue) === null || _f === void 0 ? void 0 : _f.pull_request) === null || _g === void 0 ? void 0 : _g.url.includes(`/${this.params.owner}/${this.params.repo}/`.toLowerCase()))) {
crossReferencing.push(timelineEvent.source.issue.number);
}
}
}
// If we dont have any closing info, try to get it from linked issues (PRs).
// If there's a linked issue that was closed at almost the same time, guess it was a PR that closed this.
if (!closingCommit) {
for (const id of crossReferencing.reverse()) {
const closed = await new OctoKitIssue(this.token, this.params, {
number: id,
}).getClosingInfo(alreadyChecked);
if (closed) {
if (Math.abs(closed.timestamp - ((_h = (await this.getIssue()).closedAt) !== null && _h !== void 0 ? _h : 0)) < 5000) {
closingCommit = closed;
break;
}
}
}
}
(0, utils_1.safeLog)(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`);
return closingCommit;
}
}
exports.OctoKitIssue = OctoKitIssue;
function isIssue(object) {
const isIssue = 'author' in object &&
'body' in object &&
'title' in object &&
'labels' in object &&
'open' in object &&
'locked' in object &&
'number' in object &&
'numComments' in object &&
'reactions' in object &&
'milestoneId' in object;
return isIssue;
}
//# sourceMappingURL=octokit.js.map
-559
View File
@@ -1,559 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getOctokit } from '@actions/github';
import type { RequestError } from '@octokit/request-error';
import { exec } from 'child_process';
import { IssueGetResponse, IssuesGetResponseMilestone } from '../common/OctokitTypings';
import { safeLog } from '../common/utils';
import { Comment, GitHub, GitHubIssue, Issue, Milestone, Query, User } from './api';
let numRequests = 0;
export const getNumRequests = () => numRequests;
export class OctoKit implements GitHub {
private _octokit: ReturnType<typeof getOctokit>;
protected get octokit(): ReturnType<typeof getOctokit> {
numRequests++;
return this._octokit;
}
// when in readonly mode, record labels just-created so at to not throw unneccesary errors
protected mockLabels: Set<string> = new Set();
public readonly repoName: string;
public readonly repoOwner: string;
constructor(
protected token: string,
protected params: { repo: string; owner: string },
protected options: { readonly: boolean } = { readonly: false },
) {
this._octokit = getOctokit(token);
this.repoName = params.repo;
this.repoOwner = params.owner;
}
getIssueByNumber(number: number) {
return new OctoKitIssue(this.token, this.params, { number: number });
}
// TODO: just iterate over the issues in a page here instead of making caller do it
async *query(query: Query): AsyncIterableIterator<GitHubIssue[]> {
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`;
const options = {
...query,
q,
per_page: 100,
headers: { Accept: 'application/vnd.github.squirrel-girl-preview+json' },
};
let pageNum = 0;
const timeout = async () => {
if (pageNum < 2) {
/* pass */
} else if (pageNum < 4) {
await new Promise((resolve) => setTimeout(resolve, 10000));
} else {
await new Promise((resolve) => setTimeout(resolve, 30000));
}
};
for await (const pageResponse of this.octokit.paginate.iterator(
this.octokit.rest.search.issuesAndPullRequests,
options,
)) {
await timeout();
numRequests++;
const page = pageResponse.data;
safeLog(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`);
yield page.map(
(issue) =>
new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue), this.options),
);
}
}
async createIssue(owner: string, repo: string, title: string, body: string): Promise<void> {
safeLog(`Creating issue \`${title}\` on ${owner}/${repo}`);
if (!this.options.readonly) await this.octokit.rest.issues.create({ owner, repo, title, body });
}
protected octokitIssueToIssue(issue: IssueGetResponse): Issue {
return {
author: { name: issue.user?.login ?? 'unkown', isGitHubApp: issue.user?.type === 'Bot' },
body: issue.body ?? '',
number: issue.number,
title: issue.title,
isPr: !!issue.pull_request?.html_url,
labels: issue.labels.map((label) => (typeof label === 'string' ? label : label.name ?? '')),
open: issue.state === 'open',
locked: (issue as any).locked,
numComments: issue.comments,
reactions: (issue as any).reactions,
assignee: issue.assignee?.login ?? (issue as IssueGetResponse).assignees?.[0]?.login,
assignees: (issue as IssueGetResponse).assignees?.map((assignee) => assignee.login) ?? [],
milestone: issue.milestone ? this.octokitMilestoneToMilestone(issue.milestone) : null,
createdAt: +new Date(issue.created_at),
updatedAt: +new Date(issue.updated_at),
closedAt: issue.closed_at ? +new Date(issue.closed_at as unknown as string) : undefined,
};
}
protected octokitMilestoneToMilestone(milestone: IssuesGetResponseMilestone): Milestone | null {
if (milestone?.number === undefined) {
return null;
}
return {
title: milestone.title,
milestoneId: milestone.number,
// Remove the time portions of the dates as they're not important
createdAt: milestone.created_at !== null ? new Date(milestone.created_at.split('T')[0]) : null,
dueOn: milestone.due_on !== null ? new Date(milestone.due_on.split('T')[0]) : null,
closedAt: milestone.closed_at !== null ? new Date(milestone.closed_at.split('T')[0]) : null,
description: milestone.description ?? '',
numClosedIssues: milestone.closed_issues,
numOpenIssues: milestone.open_issues,
state: milestone.state === 'open' ? 'open' : 'closed',
};
}
private writeAccessCache: Record<string, boolean> = {};
async hasWriteAccess(user: User): Promise<boolean> {
if (user.name in this.writeAccessCache) {
safeLog('Got permissions from cache for ' + user);
return this.writeAccessCache[user.name];
}
safeLog('Fetching permissions for ' + user.name);
const permissions = (
await this.octokit.rest.repos.getCollaboratorPermissionLevel({
...this.params,
username: user.name,
})
).data.permission;
return (this.writeAccessCache[user.name] = permissions === 'admin' || permissions === 'write');
}
async repoHasLabel(name: string): Promise<boolean> {
try {
await this.octokit.rest.issues.getLabel({ ...this.params, name });
return true;
} catch (err) {
const statusErorr = err as RequestError;
if (statusErorr.status === 404) {
return this.options.readonly && this.mockLabels.has(name);
}
throw err;
}
}
async createLabel(name: string, color: string, description: string): Promise<void> {
safeLog('Creating label ' + name);
if (!this.options.readonly)
await this.octokit.rest.issues.createLabel({ ...this.params, color, description, name });
else this.mockLabels.add(name);
}
async deleteLabel(name: string): Promise<void> {
safeLog('Deleting label ' + name);
try {
if (!this.options.readonly) await this.octokit.rest.issues.deleteLabel({ ...this.params, name });
} catch (err) {
const statusErorr = err as RequestError;
if (statusErorr.status === 404) {
return;
}
throw err;
}
}
async readConfig(path: string): Promise<any> {
safeLog('Reading config at ' + path);
const repoPath = `.github/${path}.json`;
try {
const data = (await this.octokit.rest.repos.getContent({ ...this.params, path: repoPath })).data;
if ('type' in data && data.type === 'file' && 'content' in data) {
if (data.encoding === 'base64' && data.content) {
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'));
}
throw Error(`Could not read contents "${data.content}" in encoding "${data.encoding}"`);
}
throw Error('Found directory at config path when expecting file' + JSON.stringify(data));
} catch (e) {
throw Error('Error with config file at ' + repoPath + ': ' + JSON.stringify(e));
}
}
async releaseContainsCommit(release: string, commit: string): Promise<'yes' | 'no' | 'unknown'> {
const isHash = (s: string) => /^[a-fA-F0-9]*$/.test(s);
if (!isHash(release) || !isHash(commit)) return 'unknown';
return new Promise((resolve, reject) =>
exec(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => {
if (!err || err.code === 1) {
resolve(!err ? 'yes' : 'no');
} else if (err.message.includes(`Not a valid commit name ${release}`)) {
// release branch is forked. Probably in endgame. Not released.
resolve('no');
} else if (err.message.includes(`Not a valid commit name ${commit}`)) {
// commit is probably in a different repo.
resolve('unknown');
} else {
reject(err);
}
}),
);
}
async getCurrentRepoMilestone(): Promise<number | undefined> {
safeLog(`Getting repo milestone for ${this.params.owner}/${this.params.repo}`);
// Fetch all milestones open for this repo
const allMilestones = (
await this.octokit.rest.issues.listMilestones({
owner: this.params.owner,
repo: this.params.repo,
state: 'open',
sort: 'due_on',
direction: 'asc',
})
).data;
const currentDate = new Date();
const possibleMilestones = allMilestones
.filter(
(milestone) =>
new Date(milestone.due_on === null ? currentDate : milestone.due_on) > currentDate &&
currentDate > new Date(milestone.created_at) &&
!milestone.title.includes('Recovery'),
)
.sort((a, b) => +new Date(a.due_on ?? currentDate) - +new Date(b.due_on ?? currentDate));
if (possibleMilestones.length === 0) {
return undefined;
}
return possibleMilestones[0].number;
}
async dispatch(title: string): Promise<void> {
safeLog('Dispatching ' + title);
if (!this.options.readonly)
await this.octokit.rest.repos.createDispatchEvent({ ...this.params, event_type: title });
}
}
export class OctoKitIssue extends OctoKit implements GitHubIssue {
constructor(
token: string,
protected params: { repo: string; owner: string },
private issueData: { number: number } | Issue,
options: { readonly: boolean } = { readonly: false },
) {
super(token, params, options);
safeLog('running bot on issue', issueData.number);
}
async addAssignee(assignee: string): Promise<void> {
safeLog('Adding assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.addAssignees({
...this.params,
issue_number: this.issueData.number,
assignees: [assignee],
});
}
}
async removeAssignee(assignee: string): Promise<void> {
safeLog('Removing assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.removeAssignees({
...this.params,
issue_number: this.issueData.number,
assignees: [assignee],
});
}
}
async closeIssue(reason: 'completed' | 'not_planned'): Promise<void> {
safeLog('Closing issue ' + this.issueData.number);
if (!this.options.readonly) {
const issue = await this.octokit.rest.issues.get({
...this.params,
issue_number: this.issueData.number,
});
// Don't close already closed issues even if it means changing the state
if (issue.data.state === 'closed') {
return;
}
await this.octokit.rest.issues
.update({
...this.params,
issue_number: this.issueData.number,
state: 'closed',
state_reason: reason,
})
.catch((e) => {
safeLog('error closing issue:', e);
});
}
}
async reopenIssue(): Promise<void> {
safeLog('Reopening issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
...this.params,
issue_number: this.issueData.number,
state: 'open',
});
}
async lockIssue(): Promise<void> {
safeLog('Locking issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.lock({ ...this.params, issue_number: this.issueData.number });
}
async unlockIssue(): Promise<void> {
safeLog('Unlocking issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.unlock({ ...this.params, issue_number: this.issueData.number });
}
async getIssue(): Promise<Issue> {
if (isIssue(this.issueData)) {
safeLog('Got issue data from query result ' + this.issueData.number);
return this.issueData;
}
safeLog('Fetching issue ' + this.issueData.number);
const issue = (
await this.octokit.rest.issues.get({
...this.params,
issue_number: this.issueData.number,
mediaType: { previews: ['squirrel-girl'] },
})
).data;
return (this.issueData = this.octokitIssueToIssue(issue));
}
async postComment(body: string): Promise<void> {
safeLog(`Posting comment on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.createComment({
...this.params,
issue_number: this.issueData.number,
body,
});
}
async deleteComment(id: number): Promise<void> {
safeLog(`Deleting comment ${id} on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.deleteComment({
owner: this.params.owner,
repo: this.params.repo,
comment_id: id,
});
}
async setMilestone(milestoneId: number) {
safeLog(`Setting milestone for ${this.issueData.number} to ${milestoneId}`);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
...this.params,
issue_number: this.issueData.number,
milestone: milestoneId,
});
}
async *getComments(last?: boolean): AsyncIterableIterator<Comment[]> {
safeLog('Fetching comments for ' + this.issueData.number);
const response = this.octokit.paginate.iterator(this.octokit.rest.issues.listComments, {
...this.params,
issue_number: this.issueData.number,
per_page: 100,
...(last ? { per_page: 1, page: (await this.getIssue()).numComments } : {}),
});
for await (const page of response) {
numRequests++;
yield page.data.map((comment) => ({
author: { name: comment.user?.login ?? '', isGitHubApp: comment.user?.type === 'Bot' },
body: comment.body ?? '',
id: comment.id,
timestamp: +new Date(comment.created_at),
}));
}
}
async addLabel(name: string): Promise<void> {
safeLog(`Adding label ${name} to ${this.issueData.number}`);
if (!(await this.repoHasLabel(name))) {
throw Error(`Action could not execute becuase label ${name} is not defined.`);
}
if (!this.options.readonly)
await this.octokit.rest.issues.addLabels({
...this.params,
issue_number: this.issueData.number,
labels: [name],
});
}
async getAssigner(assignee: string): Promise<string> {
const options = {
...this.params,
issue_number: this.issueData.number,
};
let assigner: string | undefined;
for await (const event of this.octokit.paginate.iterator(
this.octokit.rest.issues.listEventsForTimeline,
options,
)) {
numRequests++;
const timelineEvents = event.data;
for (const timelineEvent of timelineEvents) {
if (timelineEvent.event === 'assigned' && timelineEvent.assignee?.login === assignee) {
assigner = timelineEvent.actor?.login;
}
}
if (assigner) {
break;
}
}
if (!assigner) {
throw Error('Expected to find ' + assignee + ' in issue timeline but did not.');
}
return assigner;
}
async removeLabel(name: string): Promise<void> {
safeLog(`Removing label ${name} from ${this.issueData.number}`);
try {
if (!this.options.readonly)
await this.octokit.rest.issues.removeLabel({
...this.params,
issue_number: this.issueData.number,
name,
});
} catch (err) {
const statusErorr = err as RequestError;
if (statusErorr.status === 404) {
safeLog(`Label ${name} not found on issue`);
return;
}
throw err;
}
}
async getClosingInfo(
alreadyChecked: number[] = [],
): Promise<{ hash: string | undefined; timestamp: number } | undefined> {
if (alreadyChecked.includes(this.issueData.number)) {
return undefined;
}
alreadyChecked.push(this.issueData.number);
if ((await this.getIssue()).open) {
return;
}
const closingHashComment =
/(?:\\|\/)closedWith (?:https:\/\/github\.com\/microsoft\/vscode\/commit\/)?([a-fA-F0-9]{7,40})/;
const options = {
...this.params,
issue_number: this.issueData.number,
};
let closingCommit: { hash: string | undefined; timestamp: number } | undefined;
const crossReferencing: number[] = [];
for await (const event of this.octokit.paginate.iterator(
this.octokit.rest.issues.listEventsForTimeline,
options,
)) {
numRequests++;
const timelineEvents = event.data;
for (const timelineEvent of timelineEvents) {
if (
(timelineEvent.event === 'closed' || timelineEvent.event === 'merged') &&
timelineEvent.created_at &&
timelineEvent.commit_id &&
timelineEvent.commit_url
?.toLowerCase()
.includes(`/${this.params.owner}/${this.params.repo}/`.toLowerCase())
) {
closingCommit = {
hash: timelineEvent.commit_id,
timestamp: +new Date(timelineEvent.created_at),
};
}
if (timelineEvent.event === 'reopened') {
closingCommit = undefined;
}
if (
timelineEvent.created_at &&
timelineEvent.event === 'commented' &&
!((timelineEvent as any).body as string)?.includes('UNABLE_TO_LOCATE_COMMIT_MESSAGE') &&
closingHashComment.test((timelineEvent as any).body)
) {
closingCommit = {
hash: closingHashComment.exec((timelineEvent as any).body)![1],
timestamp: +new Date(timelineEvent.created_at),
};
}
if (
timelineEvent.event === 'cross-referenced' &&
(timelineEvent as any).source?.issue?.number &&
(timelineEvent as any).source?.issue?.pull_request?.url.includes(
`/${this.params.owner}/${this.params.repo}/`.toLowerCase(),
)
) {
crossReferencing.push((timelineEvent as any).source.issue.number);
}
}
}
// If we dont have any closing info, try to get it from linked issues (PRs).
// If there's a linked issue that was closed at almost the same time, guess it was a PR that closed this.
if (!closingCommit) {
for (const id of crossReferencing.reverse()) {
const closed = await new OctoKitIssue(this.token, this.params, {
number: id,
}).getClosingInfo(alreadyChecked);
if (closed) {
if (Math.abs(closed.timestamp - ((await this.getIssue()).closedAt ?? 0)) < 5000) {
closingCommit = closed;
break;
}
}
}
}
safeLog(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`);
return closingCommit;
}
}
function isIssue(object: any): object is Issue {
const isIssue =
'author' in object &&
'body' in object &&
'title' in object &&
'labels' in object &&
'open' in object &&
'locked' in object &&
'number' in object &&
'numComments' in object &&
'reactions' in object &&
'milestoneId' in object;
return isIssue;
}
-144
View File
@@ -1,144 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Action = void 0;
const octokit_1 = require("../api/octokit");
const github_1 = require("@actions/github");
const utils_1 = require("./utils");
const core_1 = require("@actions/core");
class Action {
constructor() {
this.token = (0, utils_1.getRequiredInput)('token');
this.username = (0, github_1.getOctokit)(this.token)
.rest.users.getAuthenticated()
.then((v) => { var _a; return (_a = v.data.name) !== null && _a !== void 0 ? _a : 'unknown'; }, () => 'unknown');
}
async run() {
var _a, _b, _c, _d, _e, _f;
if (utils_1.errorLoggingIssue) {
const { repo, issue, owner } = utils_1.errorLoggingIssue;
if (github_1.context.repo.repo === repo &&
github_1.context.repo.owner === owner &&
((_a = github_1.context.payload.issue) === null || _a === void 0 ? void 0 : _a.number) === issue) {
return (0, utils_1.safeLog)('refusing to run on error logging issue to prevent cascading errors');
}
}
try {
const token = (0, utils_1.getRequiredInput)('token');
const readonly = !!(0, core_1.getInput)('readonly');
const issue = (_b = github_1.context === null || github_1.context === void 0 ? void 0 : github_1.context.issue) === null || _b === void 0 ? void 0 : _b.number;
if (issue) {
const octokit = new octokit_1.OctoKitIssue(token, github_1.context.repo, { number: issue }, { readonly });
if (github_1.context.eventName === 'issue_comment') {
await this.onCommented(octokit, (_c = github_1.context.payload.comment) === null || _c === void 0 ? void 0 : _c.body, github_1.context.actor);
}
else if (github_1.context.eventName === 'issues' ||
github_1.context.eventName === 'pull_request' ||
github_1.context.eventName === 'pull_request_target') {
switch (github_1.context.payload.action) {
case 'opened':
case 'ready_for_review':
await this.onOpened(octokit, github_1.context.payload);
break;
case 'reopened':
await this.onReopened(octokit);
break;
case 'closed':
await this.onClosed(octokit, github_1.context.payload);
break;
case 'labeled':
await this.onLabeled(octokit, github_1.context.payload.label.name);
break;
case 'assigned':
await this.onAssigned(octokit, github_1.context.payload.assignee.login);
break;
case 'unassigned':
await this.onUnassigned(octokit, github_1.context.payload.assignee.login);
break;
case 'edited':
await this.onEdited(octokit);
break;
case 'milestoned':
await this.onMilestoned(octokit);
break;
default:
throw Error('Unexpected action: ' + github_1.context.payload.action);
}
}
}
else if (github_1.context.eventName === 'create') {
await this.onCreated(new octokit_1.OctoKit(token, github_1.context.repo, { readonly }), (_d = github_1.context === null || github_1.context === void 0 ? void 0 : github_1.context.payload) === null || _d === void 0 ? void 0 : _d.ref, (_f = (_e = github_1.context === null || github_1.context === void 0 ? void 0 : github_1.context.payload) === null || _e === void 0 ? void 0 : _e.sender) === null || _f === void 0 ? void 0 : _f.login);
}
else {
await this.onTriggered(new octokit_1.OctoKit(token, github_1.context.repo, { readonly }));
}
}
catch (e) {
const err = e;
try {
await this.error(err);
}
catch {
(0, utils_1.safeLog)((err === null || err === void 0 ? void 0 : err.stack) || (err === null || err === void 0 ? void 0 : err.message) || String(e));
}
}
const usage = await (0, utils_1.getRateLimit)(this.token);
}
async error(error) {
var _a;
const details = {
message: `${error.message}\n${error.stack}`,
id: this.id,
user: await this.username,
};
if ((_a = github_1.context.issue) === null || _a === void 0 ? void 0 : _a.number)
details.issue = github_1.context.issue.number;
const rendered = `
Message: ${details.message}
Actor: ${details.user}
ID: ${details.id}
`;
await (0, utils_1.logErrorToIssue)(rendered, true, this.token);
(0, core_1.setFailed)(error.message);
}
async onTriggered(_octokit) {
throw Error('not implemented');
}
async onCreated(_octokit, _ref, _creator) {
throw Error('not implemented');
}
async onEdited(_issue) {
throw Error('not implemented');
}
async onLabeled(_issue, _label) {
throw Error('not implemented');
}
async onAssigned(_issue, _assignee) {
throw Error('not implemented');
}
async onUnassigned(_issue, _assignee) {
throw Error('not implemented');
}
async onOpened(_issue, _payload) {
throw Error('not implemented');
}
async onReopened(_issue) {
throw Error('not implemented');
}
async onClosed(_issue, _payload) {
throw Error('not implemented');
}
async onMilestoned(_issue) {
throw Error('not implemented');
}
async onCommented(_issue, _comment, _actor) {
throw Error('not implemented');
}
}
exports.Action = Action;
//# sourceMappingURL=Action.js.map
-158
View File
@@ -1,158 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { OctoKit, OctoKitIssue, getNumRequests } from '../api/octokit';
import { context, getOctokit } from '@actions/github';
import { getRequiredInput, logErrorToIssue, getRateLimit, errorLoggingIssue, safeLog } from './utils';
import { getInput, setFailed } from '@actions/core';
import { WebhookPayload } from '@actions/github/lib/interfaces';
export abstract class Action {
abstract id: string;
private username: Promise<string>;
private token = getRequiredInput('token');
constructor() {
this.username = getOctokit(this.token)
.rest.users.getAuthenticated()
.then(
(v) => v.data.name ?? 'unknown',
() => 'unknown',
);
}
public async run() {
if (errorLoggingIssue) {
const { repo, issue, owner } = errorLoggingIssue;
if (
context.repo.repo === repo &&
context.repo.owner === owner &&
context.payload.issue?.number === issue
) {
return safeLog('refusing to run on error logging issue to prevent cascading errors');
}
}
try {
const token = getRequiredInput('token');
const readonly = !!getInput('readonly');
const issue = context?.issue?.number;
if (issue) {
const octokit = new OctoKitIssue(token, context.repo, { number: issue }, { readonly });
if (context.eventName === 'issue_comment') {
await this.onCommented(octokit, context.payload.comment?.body, context.actor);
} else if (
context.eventName === 'issues' ||
context.eventName === 'pull_request' ||
context.eventName === 'pull_request_target'
) {
switch (context.payload.action) {
case 'opened':
case 'ready_for_review':
await this.onOpened(octokit, context.payload);
break;
case 'reopened':
await this.onReopened(octokit);
break;
case 'closed':
await this.onClosed(octokit, context.payload);
break;
case 'labeled':
await this.onLabeled(octokit, context.payload.label.name);
break;
case 'assigned':
await this.onAssigned(octokit, context.payload.assignee.login);
break;
case 'unassigned':
await this.onUnassigned(octokit, context.payload.assignee.login);
break;
case 'edited':
await this.onEdited(octokit);
break;
case 'milestoned':
await this.onMilestoned(octokit);
break;
default:
throw Error('Unexpected action: ' + context.payload.action);
}
}
} else if (context.eventName === 'create') {
await this.onCreated(
new OctoKit(token, context.repo, { readonly }),
context?.payload?.ref,
context?.payload?.sender?.login,
);
} else {
await this.onTriggered(new OctoKit(token, context.repo, { readonly }));
}
} catch (e) {
const err = e as Error;
try {
await this.error(err);
} catch {
safeLog(err?.stack || err?.message || String(e));
}
}
const usage = await getRateLimit(this.token);
}
private async error(error: Error) {
const details: any = {
message: `${error.message}\n${error.stack}`,
id: this.id,
user: await this.username,
};
if (context.issue?.number) details.issue = context.issue.number;
const rendered = `
Message: ${details.message}
Actor: ${details.user}
ID: ${details.id}
`;
await logErrorToIssue(rendered, true, this.token);
setFailed(error.message);
}
protected async onTriggered(_octokit: OctoKit): Promise<void> {
throw Error('not implemented');
}
protected async onCreated(_octokit: OctoKit, _ref: string, _creator: string): Promise<void> {
throw Error('not implemented');
}
protected async onEdited(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
}
protected async onLabeled(_issue: OctoKitIssue, _label: string): Promise<void> {
throw Error('not implemented');
}
protected async onAssigned(_issue: OctoKitIssue, _assignee: string): Promise<void> {
throw Error('not implemented');
}
protected async onUnassigned(_issue: OctoKitIssue, _assignee: string): Promise<void> {
throw Error('not implemented');
}
protected async onOpened(_issue: OctoKitIssue, _payload: WebhookPayload): Promise<void> {
throw Error('not implemented');
}
protected async onReopened(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
}
protected async onClosed(_issue: OctoKitIssue, _payload: WebhookPayload): Promise<void> {
throw Error('not implemented');
}
protected async onMilestoned(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
}
protected async onCommented(_issue: OctoKitIssue, _comment: string, _actor: string): Promise<void> {
throw Error('not implemented');
}
}
-183
View File
@@ -1,183 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActionBase = void 0;
const utils_1 = require("./utils");
class ActionBase {
constructor(labels, milestoneName, milestoneId, ignoreLabels, ignoreMilestoneNames, ignoreMilestoneIds, minimumVotes, maximumVotes, involves) {
this.labels = labels;
this.milestoneName = milestoneName;
this.milestoneId = milestoneId;
this.ignoreLabels = ignoreLabels;
this.ignoreMilestoneNames = ignoreMilestoneNames;
this.ignoreMilestoneIds = ignoreMilestoneIds;
this.minimumVotes = minimumVotes;
this.maximumVotes = maximumVotes;
this.involves = involves;
this.labelsSet = [];
this.ignoreLabelsSet = [];
this.ignoreMilestoneNamesSet = [];
this.ignoreMilestoneIdsSet = [];
this.ignoreAllWithLabels = false;
this.ignoreAllWithMilestones = false;
this.involvesSet = [];
}
buildQuery(baseQuery) {
var _a, _b, _c, _d, _e, _f;
let query = baseQuery;
(0, utils_1.safeLog)(`labels: ${this.labels}`);
(0, utils_1.safeLog)(`milestoneName: ${this.milestoneName}`);
(0, utils_1.safeLog)(`milestoneId: ${this.milestoneId}`);
(0, utils_1.safeLog)(`ignoreLabels: ${this.ignoreLabels}`);
(0, utils_1.safeLog)(`ignoreMilestoneNames: ${this.ignoreMilestoneNames}`);
(0, utils_1.safeLog)(`ignoreMilestoneIds: ${this.ignoreMilestoneIds}`);
(0, utils_1.safeLog)(`minimumVotes: ${this.minimumVotes}`);
(0, utils_1.safeLog)(`maximumVotes: ${this.maximumVotes}`);
(0, utils_1.safeLog)(`involves: ${this.involves}`);
// Both milestone name and milestone Id must be provided and must match.
// The name is used to construct the query, which does not accept ID.
// The ID is used for comparisons with issue data, which does not include the name.
// TODO: Figure out a way to convert either from milestone name to ID, or vice versa.
// If label inclusion and exclusion are mixed, exclusion will take precedence.
// For example, an issue with both labels A and B will not match if B is excluded, even if A is included.
// If a milestoneName/milestoneId are set, ignoreMilenameName/ignoreMilestoneIds are ignored.
// GitHub does not appear to support searching for all issues with milestones (not lacking a milestone). "-no:milestone" does not work.
// GitHub does not appear to support searching for all issues with labels (not lacking a label). "-no:label" does not work.
// All indicated labels must be present
if (this.labels) {
if (((_a = this.labels) === null || _a === void 0 ? void 0 : _a.length) > 2 && ((_b = this.labels) === null || _b === void 0 ? void 0 : _b.startsWith('"')) && ((_c = this.labels) === null || _c === void 0 ? void 0 : _c.endsWith('"'))) {
this.labels = this.labels.substring(1, this.labels.length - 2);
}
this.labelsSet = (_d = this.labels) === null || _d === void 0 ? void 0 : _d.split(',');
for (const str of this.labelsSet) {
if (str != "") {
query = query.concat(` label:"${str}"`);
}
}
}
// The "involves" qualifier to find issues that in some way involve a certain user.
// It is a logical OR between the author, assignee, and mentions.
if (this.involves) {
this.involvesSet = (_e = this.involves) === null || _e === void 0 ? void 0 : _e.split(',');
for (const str of this.involvesSet) {
if (str != "") {
query = query.concat(` involves:"${str}"`);
}
}
}
if (this.ignoreLabels) {
if (this.ignoreLabels == "*" && !this.labels) { // only if unlabeled
query = query.concat(` no:label`);
this.ignoreAllWithLabels = true;
}
else {
this.ignoreLabelsSet = (_f = this.ignoreLabels) === null || _f === void 0 ? void 0 : _f.split(',');
for (const str of this.ignoreLabelsSet) {
if (str != "") {
query = query.concat(` -label:"${str}"`);
}
}
}
}
if (this.milestoneName) {
query = query.concat(` milestone:"${this.milestoneName}"`);
}
else if (this.ignoreMilestoneNames) {
if (this.ignoreMilestoneNames == "*") {
query = query.concat(` no:milestone`);
this.ignoreAllWithMilestones = true;
}
else if (this.ignoreMilestoneIds) {
this.ignoreMilestoneNamesSet = this.ignoreMilestoneNames.split(',');
this.ignoreMilestoneIdsSet = this.ignoreMilestoneIds.split(',');
for (const str of this.ignoreMilestoneNamesSet) {
if (str != "") {
query = query.concat(` -milestone:"${str}"`);
}
}
}
}
return query;
}
// This is necessary because GitHub sometimes returns incorrect results,
// and because issues may get modified while we are processing them.
validateIssue(issue) {
var _a, _b;
if (this.ignoreAllWithLabels) {
// Validate that the issue does not have labels
if (issue.labels && issue.labels.length !== 0) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to label found after querying for no:label.`);
return false;
}
}
else {
// Make sure all labels we wanted are present.
if ((!issue.labels || issue.labels.length == 0) && this.labelsSet.length > 0) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to not having a required label set. No labels found.`);
return false;
}
for (const str of this.labelsSet) {
if (!issue.labels.includes(str)) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to not having a required label set.`);
return false;
}
}
// Make sure no labels we wanted to ignore are present.
if (issue.labels && issue.labels.length > 0) {
for (const str of this.ignoreLabelsSet) {
if (issue.labels.includes(str)) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to having an ignore label set: ${str}`);
return false;
}
}
}
}
if (this.ignoreAllWithMilestones) {
// Validate that the issue does not have a milestone.
if (issue.milestone) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to milestone found after querying for no:milestone.`);
return false;
}
}
else {
// Make sure milestone is present, if required.
if (this.milestoneId != null && ((_a = issue.milestone) === null || _a === void 0 ? void 0 : _a.milestoneId) != +this.milestoneId) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to not having required milsetone id ${this.milestoneId}. Had: ${(_b = issue.milestone) === null || _b === void 0 ? void 0 : _b.milestoneId}`);
return false;
}
// Make sure a milestones we wanted to ignore is not present.
if (issue.milestone && issue.milestone.milestoneId != null) {
for (const str of this.ignoreMilestoneIdsSet) {
if (issue.milestone.milestoneId == +str) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to milestone ${issue.milestone.milestoneId} found in list of ignored milestone IDs.`);
return false;
}
}
}
}
// Verify the issue has a sufficient number of upvotes
let upvotes = 0;
if (issue.reactions) {
upvotes = issue.reactions['+1'];
}
if (this.minimumVotes != undefined) {
if (upvotes < this.minimumVotes) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to not having at least ${this.minimumVotes} upvotes. Had: ${upvotes}`);
return false;
}
}
// Verify the issue does not have too many upvotes
if (this.maximumVotes != undefined) {
if (upvotes > this.maximumVotes) {
(0, utils_1.safeLog)(`Issue ${issue.number} skipped due to having more than ${this.maximumVotes} upvotes. Had: ${upvotes}`);
return false;
}
}
return true;
}
}
exports.ActionBase = ActionBase;
//# sourceMappingURL=ActionBase.js.map
-188
View File
@@ -1,188 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Issue } from '../api/api'
import { safeLog } from './utils';
export class ActionBase {
constructor(
private labels?: string,
private milestoneName?: string,
private milestoneId?: string,
private ignoreLabels?: string,
private ignoreMilestoneNames?: string,
private ignoreMilestoneIds?: string,
private minimumVotes?: number,
private maximumVotes?: number,
private involves?: string,
) {}
private labelsSet: string[] = [];
private ignoreLabelsSet: string[] = [];
private ignoreMilestoneNamesSet: string[] = [];
private ignoreMilestoneIdsSet: string[] = [];
private ignoreAllWithLabels: boolean = false;
private ignoreAllWithMilestones: boolean = false;
private involvesSet: string[] = [];
buildQuery(baseQuery: string): string {
let query = baseQuery;
safeLog(`labels: ${this.labels}`);
safeLog(`milestoneName: ${this.milestoneName}`);
safeLog(`milestoneId: ${this.milestoneId}`);
safeLog(`ignoreLabels: ${this.ignoreLabels}`);
safeLog(`ignoreMilestoneNames: ${this.ignoreMilestoneNames}`);
safeLog(`ignoreMilestoneIds: ${this.ignoreMilestoneIds}`);
safeLog(`minimumVotes: ${this.minimumVotes}`);
safeLog(`maximumVotes: ${this.maximumVotes}`);
safeLog(`involves: ${this.involves}`);
// Both milestone name and milestone Id must be provided and must match.
// The name is used to construct the query, which does not accept ID.
// The ID is used for comparisons with issue data, which does not include the name.
// TODO: Figure out a way to convert either from milestone name to ID, or vice versa.
// If label inclusion and exclusion are mixed, exclusion will take precedence.
// For example, an issue with both labels A and B will not match if B is excluded, even if A is included.
// If a milestoneName/milestoneId are set, ignoreMilenameName/ignoreMilestoneIds are ignored.
// GitHub does not appear to support searching for all issues with milestones (not lacking a milestone). "-no:milestone" does not work.
// GitHub does not appear to support searching for all issues with labels (not lacking a label). "-no:label" does not work.
// All indicated labels must be present
if (this.labels) {
if (this.labels?.length > 2 && this.labels?.startsWith('"') && this.labels?.endsWith('"')) {
this.labels = this.labels.substring(1, this.labels.length - 2);
}
this.labelsSet = this.labels?.split(',');
for (const str of this.labelsSet) {
if (str != "") {
query = query.concat(` label:"${str}"`);
}
}
}
// The "involves" qualifier to find issues that in some way involve a certain user.
// It is a logical OR between the author, assignee, and mentions.
if (this.involves) {
this.involvesSet = this.involves?.split(',');
for (const str of this.involvesSet) {
if (str != "") {
query = query.concat(` involves:"${str}"`)
}
}
}
if (this.ignoreLabels) {
if (this.ignoreLabels == "*" && !this.labels) { // only if unlabeled
query = query.concat(` no:label`)
this.ignoreAllWithLabels = true;
} else {
this.ignoreLabelsSet = this.ignoreLabels?.split(',');
for (const str of this.ignoreLabelsSet) {
if (str != "") {
query = query.concat(` -label:"${str}"`)
}
}
}
}
if (this.milestoneName) {
query = query.concat(` milestone:"${this.milestoneName}"`)
}
else if (this.ignoreMilestoneNames) {
if (this.ignoreMilestoneNames == "*") {
query = query.concat(` no:milestone`)
this.ignoreAllWithMilestones = true;
} else if (this.ignoreMilestoneIds) {
this.ignoreMilestoneNamesSet = this.ignoreMilestoneNames.split(',');
this.ignoreMilestoneIdsSet = this.ignoreMilestoneIds.split(',');
for (const str of this.ignoreMilestoneNamesSet) {
if (str != "") {
query = query.concat(` -milestone:"${str}"`)
}
}
}
}
return query;
}
// This is necessary because GitHub sometimes returns incorrect results,
// and because issues may get modified while we are processing them.
validateIssue(issue: Issue): boolean {
if (this.ignoreAllWithLabels) {
// Validate that the issue does not have labels
if (issue.labels && issue.labels.length !== 0) {
safeLog(`Issue ${issue.number} skipped due to label found after querying for no:label.`);
return false;
}
} else {
// Make sure all labels we wanted are present.
if ((!issue.labels || issue.labels.length == 0) && this.labelsSet.length > 0) {
safeLog(`Issue ${issue.number} skipped due to not having a required label set. No labels found.`);
return false;
}
for (const str of this.labelsSet) {
if (!issue.labels.includes(str)) {
safeLog(`Issue ${issue.number} skipped due to not having a required label set.`);
return false;
}
}
// Make sure no labels we wanted to ignore are present.
if (issue.labels && issue.labels.length > 0) {
for (const str of this.ignoreLabelsSet) {
if (issue.labels.includes(str)) {
safeLog(`Issue ${issue.number} skipped due to having an ignore label set: ${str}`);
return false;
}
}
}
}
if (this.ignoreAllWithMilestones) {
// Validate that the issue does not have a milestone.
if (issue.milestone) {
safeLog(`Issue ${issue.number} skipped due to milestone found after querying for no:milestone.`);
return false;
}
} else {
// Make sure milestone is present, if required.
if (this.milestoneId != null && issue.milestone?.milestoneId != +this.milestoneId) {
safeLog(`Issue ${issue.number} skipped due to not having required milsetone id ${this.milestoneId}. Had: ${issue.milestone?.milestoneId}`);
return false;
}
// Make sure a milestones we wanted to ignore is not present.
if (issue.milestone && issue.milestone.milestoneId != null) {
for (const str of this.ignoreMilestoneIdsSet) {
if (issue.milestone.milestoneId == +str) {
safeLog(`Issue ${issue.number} skipped due to milestone ${issue.milestone.milestoneId} found in list of ignored milestone IDs.`);
return false;
}
}
}
}
// Verify the issue has a sufficient number of upvotes
let upvotes = 0;
if (issue.reactions) {
upvotes = issue.reactions['+1'];
}
if (this.minimumVotes != undefined) {
if (upvotes < this.minimumVotes) {
safeLog(`Issue ${issue.number} skipped due to not having at least ${this.minimumVotes} upvotes. Had: ${upvotes}`);
return false;
}
}
// Verify the issue does not have too many upvotes
if (this.maximumVotes != undefined) {
if (upvotes > this.maximumVotes) {
safeLog(`Issue ${issue.number} skipped due to having more than ${this.maximumVotes} upvotes. Had: ${upvotes}`);
return false;
}
}
return true;
}
}
-7
View File
@@ -1,7 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=OctokitTypings.js.map
-16
View File
@@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { RestEndpointMethodTypes } from '@octokit/rest';
// This file is just to re-export some octokit types as nicer names
export type ActionsListWorkflowRunsResponseWorkflowRunsItem =
RestEndpointMethodTypes['actions']['listWorkflowRuns']['response']['data']['workflow_runs'][0];
export type IssueGetResponse = RestEndpointMethodTypes['issues']['get']['response']['data'];
export type IssuesGetResponseMilestone =
RestEndpointMethodTypes['issues']['get']['response']['data']['milestone'];
-119
View File
@@ -1,119 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeLog = exports.logErrorToIssue = exports.errorLoggingIssue = exports.getRateLimit = exports.daysAgoToHumanReadbleDate = exports.daysAgoToTimestamp = exports.loadLatestRelease = exports.normalizeIssue = exports.getRequiredInput = exports.getInput = void 0;
const core = require("@actions/core");
const github_1 = require("@actions/github");
const axios_1 = require("axios");
const octokit_1 = require("../api/octokit");
const getInput = (name) => core.getInput(name) || undefined;
exports.getInput = getInput;
const getRequiredInput = (name) => core.getInput(name, { required: true });
exports.getRequiredInput = getRequiredInput;
const normalizeIssue = (issue) => {
let { body, title } = issue;
body = body !== null && body !== void 0 ? body : '';
title = title !== null && title !== void 0 ? title : '';
const isBug = body.includes('bug_report_template') || /Issue Type:.*Bug.*/.test(body);
const isFeatureRequest = body.includes('feature_request_template') || /Issue Type:.*Feature Request.*/.test(body);
const cleanse = (str) => {
let out = str
.toLowerCase()
.replace(/<!--.*-->/gu, '')
.replace(/.* version: .*/gu, '')
.replace(/issue type: .*/gu, '')
.replace(/vs ?code/gu, '')
.replace(/we have written.*please paste./gu, '')
.replace(/steps to reproduce:/gu, '')
.replace(/does this issue occur when all extensions are disabled.*/gu, '')
.replace(/!?\[[^\]]*\]\([^)]*\)/gu, '')
.replace(/\s+/gu, ' ')
.replace(/```[^`]*?```/gu, '');
while (out.includes(`<details>`) &&
out.includes('</details>') &&
out.indexOf(`</details>`) > out.indexOf(`<details>`)) {
out = out.slice(0, out.indexOf('<details>')) + out.slice(out.indexOf(`</details>`) + 10);
}
return out;
};
return {
body: cleanse(body),
title: cleanse(title),
issueType: isBug ? 'bug' : isFeatureRequest ? 'feature_request' : 'unknown',
};
};
exports.normalizeIssue = normalizeIssue;
const loadLatestRelease = async (quality) => (await axios_1.default.get(`https://update.code.visualstudio.com/api/update/darwin/${quality}/latest`)).data;
exports.loadLatestRelease = loadLatestRelease;
const daysAgoToTimestamp = (days) => +new Date(Date.now() - days * 24 * 60 * 60 * 1000);
exports.daysAgoToTimestamp = daysAgoToTimestamp;
const daysAgoToHumanReadbleDate = (days) => new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '');
exports.daysAgoToHumanReadbleDate = daysAgoToHumanReadbleDate;
const getRateLimit = async (token) => {
const usageData = (await (0, github_1.getOctokit)(token).rest.rateLimit.get()).data.resources;
const usage = {};
['core', 'graphql', 'search'].forEach(async (category) => {
var _a, _b, _c, _d;
if (usageData[category]) {
usage[category] = 1 - ((_b = (_a = usageData[category]) === null || _a === void 0 ? void 0 : _a.remaining) !== null && _b !== void 0 ? _b : 0) / ((_d = (_c = usageData[category]) === null || _c === void 0 ? void 0 : _c.limit) !== null && _d !== void 0 ? _d : 1);
}
});
return usage;
};
exports.getRateLimit = getRateLimit;
exports.errorLoggingIssue = (() => {
try {
const repo = github_1.context.repo.owner.toLowerCase() + '/' + github_1.context.repo.repo.toLowerCase();
if (repo === 'microsoft/vscode' || repo === 'microsoft/vscode-remote-release') {
return { repo: 'vscode', owner: 'Microsoft', issue: 93814 };
}
else if (/microsoft\//.test(repo)) {
return { repo: 'vscode-internalbacklog', owner: 'Microsoft', issue: 974 };
}
else if ((0, exports.getInput)('errorLogIssueNumber')) {
return { ...github_1.context.repo, issue: +(0, exports.getRequiredInput)('errorLogIssueNumber') };
}
else {
return undefined;
}
}
catch (e) {
console.error(e);
return undefined;
}
})();
const logErrorToIssue = async (message, ping, token) => {
var _a;
// Attempt to wait out abuse detection timeout if present
await new Promise((resolve) => setTimeout(resolve, 10000));
const dest = exports.errorLoggingIssue;
if (!dest)
return console.log('no error logging repo defined. swallowing error.');
return new octokit_1.OctoKitIssue(token, { owner: dest.owner, repo: dest.repo }, { number: dest.issue })
.postComment(`
Workflow: ${github_1.context.workflow}
Error: ${message}
Issue: ${ping ? `${github_1.context.repo.owner}/${github_1.context.repo.repo}#` : ''}${(_a = github_1.context.issue) === null || _a === void 0 ? void 0 : _a.number}
Repo: ${github_1.context.repo.owner}/${github_1.context.repo.repo}
<!-- Context:
${JSON.stringify(github_1.context, null, 2)
.replace(/<!--/gu, '<@--')
.replace(/-->/gu, '--@>')
.replace(/\/|\\/gu, 'slash-')}
-->
`);
};
exports.logErrorToIssue = logErrorToIssue;
const safeLog = (message, ...args) => {
const clean = (val) => ('' + val).replace(/:|#/g, '');
console.log(clean(message), ...args.map(clean));
};
exports.safeLog = safeLog;
//# sourceMappingURL=utils.js.map
-129
View File
@@ -1,129 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as core from '@actions/core';
import { context, getOctokit } from '@actions/github';
import axios from 'axios';
import { OctoKitIssue } from '../api/octokit';
export const getInput = (name: string) => core.getInput(name) || undefined;
export const getRequiredInput = (name: string) => core.getInput(name, { required: true });
export const normalizeIssue = (issue: {
body: string;
title: string;
}): { body: string; title: string; issueType: 'bug' | 'feature_request' | 'unknown' } => {
let { body, title } = issue;
body = body ?? '';
title = title ?? '';
const isBug = body.includes('bug_report_template') || /Issue Type:.*Bug.*/.test(body);
const isFeatureRequest =
body.includes('feature_request_template') || /Issue Type:.*Feature Request.*/.test(body);
const cleanse = (str: string) => {
let out = str
.toLowerCase()
.replace(/<!--.*-->/gu, '')
.replace(/.* version: .*/gu, '')
.replace(/issue type: .*/gu, '')
.replace(/vs ?code/gu, '')
.replace(/we have written.*please paste./gu, '')
.replace(/steps to reproduce:/gu, '')
.replace(/does this issue occur when all extensions are disabled.*/gu, '')
.replace(/!?\[[^\]]*\]\([^)]*\)/gu, '')
.replace(/\s+/gu, ' ')
.replace(/```[^`]*?```/gu, '');
while (
out.includes(`<details>`) &&
out.includes('</details>') &&
out.indexOf(`</details>`) > out.indexOf(`<details>`)
) {
out = out.slice(0, out.indexOf('<details>')) + out.slice(out.indexOf(`</details>`) + 10);
}
return out;
};
return {
body: cleanse(body),
title: cleanse(title),
issueType: isBug ? 'bug' : isFeatureRequest ? 'feature_request' : 'unknown',
};
};
export interface Release {
productVersion: string;
timestamp: number;
version: string;
}
export const loadLatestRelease = async (quality: 'stable' | 'insider'): Promise<Release | undefined> =>
(await axios.get(`https://update.code.visualstudio.com/api/update/darwin/${quality}/latest`)).data;
export const daysAgoToTimestamp = (days: number): number =>
+new Date(Date.now() - days * 24 * 60 * 60 * 1000);
export const daysAgoToHumanReadbleDate = (days: number) =>
new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '');
export const getRateLimit = async (token: string) => {
const usageData = (await getOctokit(token).rest.rateLimit.get()).data.resources;
const usage = {} as { core: number; graphql: number; search: number };
(['core', 'graphql', 'search'] as const).forEach(async (category) => {
if (usageData[category]) {
usage[category] = 1 - (usageData[category]?.remaining ?? 0) / (usageData[category]?.limit ?? 1);
}
});
return usage;
};
export const errorLoggingIssue = (() => {
try {
const repo = context.repo.owner.toLowerCase() + '/' + context.repo.repo.toLowerCase();
if (repo === 'microsoft/vscode' || repo === 'microsoft/vscode-remote-release') {
return { repo: 'vscode', owner: 'Microsoft', issue: 93814 };
} else if (/microsoft\//.test(repo)) {
return { repo: 'vscode-internalbacklog', owner: 'Microsoft', issue: 974 };
} else if (getInput('errorLogIssueNumber')) {
return { ...context.repo, issue: +getRequiredInput('errorLogIssueNumber') };
} else {
return undefined;
}
} catch (e) {
console.error(e);
return undefined;
}
})();
export const logErrorToIssue = async (message: string, ping: boolean, token: string): Promise<void> => {
// Attempt to wait out abuse detection timeout if present
await new Promise((resolve) => setTimeout(resolve, 10000));
const dest = errorLoggingIssue;
if (!dest) return console.log('no error logging repo defined. swallowing error.');
return new OctoKitIssue(token, { owner: dest.owner, repo: dest.repo }, { number: dest.issue })
.postComment(`
Workflow: ${context.workflow}
Error: ${message}
Issue: ${ping ? `${context.repo.owner}/${context.repo.repo}#` : ''}${context.issue?.number}
Repo: ${context.repo.owner}/${context.repo.repo}
<!-- Context:
${JSON.stringify(context, null, 2)
.replace(/<!--/gu, '<@--')
.replace(/-->/gu, '--@>')
.replace(/\/|\\/gu, 'slash-')}
-->
`);
};
export const safeLog = (message: string, ...args: (string | number | string[])[]): void => {
const clean = (val: any) => ('' + val).replace(/:|#/g, '');
console.log(clean(message), ...args.map(clean));
};
-5686
View File
File diff suppressed because it is too large Load Diff
-45
View File
@@ -1,45 +0,0 @@
{
"name": "vscode-cpptools-github-triage-actions",
"version": "1.0.0",
"description": "GitHub Actions used by VS Code cpptools for triaging issues",
"scripts": {
"build": "tsc",
"lint": "eslint -c .eslintrc --fix --ext .ts .",
"watch": "tsc --watch"
},
"keywords": [],
"author": "",
"dependencies": {
"@actions/core": "^1.9.1",
"@actions/github": "^5.0.3",
"@octokit/rest": "^19.0.3",
"@slack/web-api": "^6.9.1",
"applicationinsights": "^2.5.1",
"axios": "^1.6.1",
"uuid": "^8.3.2"
},
"devDependencies": {
"@azure/storage-blob": "^12.13.0",
"@types/chai": "^4.3.3",
"@types/mocha": "^9.1.1",
"@types/uuid": "^8.3.4",
"@types/yargs": "^17.0.11",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"chai": "^4.3.6",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1",
"mocha": "^10.0.0",
"mongodb": "^4.17.0",
"nock": "^13.2.9",
"prettier": "2.7.1",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"yargs": "^17.5.1"
},
"resolutions": {
"minimatch": "^3.0.5"
}
}
-19
View File
@@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es2019",
"strict": true,
"module": "commonjs",
"moduleResolution": "node",
"removeComments": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"lib": [
"es2020"
]
},
"exclude": [
"**/*.test.ts",
"**/vm-filesystem/**"
]
}
@@ -1,28 +0,0 @@
name: By Design closer - debugger
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v3
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: by design,debugger
ignoreLabels: language service,internal
closeDays: 0
closeComment: "This issue has been closed because the described behavior was determined to be by design."
-30
View File
@@ -1,30 +0,0 @@
name: By Design Closer
on:
schedule:
- cron: 0 12 * * * # Run at 12:00 PM UTC (4:00 AM PST, 5:00 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v3
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: by design
ignoreLabels: debugger,Feature Request,more info needed,internal
closeDays: 60
closeComment: "This issue has been closed because the described behavior was determined to be by design."
pingDays: 80
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if it is no longer relevant."
-14
View File
@@ -1,14 +0,0 @@
name: CI (Linux)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: ubuntu-22.04
platform: linux
-15
View File
@@ -1,15 +0,0 @@
name: CI (Mac)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: macos-12
platform: mac
yarn-args: --network-timeout 100000
-14
View File
@@ -1,14 +0,0 @@
name: CI (Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: windows-2022
platform: windows
-30
View File
@@ -1,30 +0,0 @@
name: Duplicate Closer
on:
schedule:
- cron: 10 12 * * * # Run at 12:10 PM UTC (4:10 AM PST, 5:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: duplicate
ignoreLabels: debugger,Feature Request,more info needed,by design,internal
closeDays: 60
closeComment: "This issue has been closed because it is a duplicate of another issue we are tracking."
pingDays: 80
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if it is no longer relevant."
@@ -1,32 +0,0 @@
name: Enhancement Closer (no milestone)
on:
schedule:
- cron: 50 11 * * * # Run at 11:50 AM UTC (3:50 AM PST, 4:50 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: enhancement
ignoreLabels: debugger,internal,Feature Request
addLabels: more votes needed
closeDays: 60
maximumVotes: 2
closeComment: "This feature request is being closed due to insufficient upvotes. Please leave a 👍-upvote or 👎-downvote reaction on the issue to help us prioritize it. When enough upvotes are received, this issue will be eligible for our backlog."
setMilestoneId: 30
ignoreMilestoneNames: "*"
@@ -1,32 +0,0 @@
name: Enhancement Closer (Triage)
on:
schedule:
- cron: 40 11 * * * # Run at 11:40 AM UTC (3:40 AM PST, 4:40 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: enhancement
ignoreLabels: debugger,internal,Feature Request
addLabels: more votes needed
closeDays: 60
maximumVotes: 2
closeComment: "This feature request is being closed due to insufficient upvotes. Please leave a 👍-upvote or 👎-downvote reaction on the issue to help us prioritize it. When enough upvotes are received, this issue will be eligible for our backlog."
milestoneName: Triage
milestoneId: 30
@@ -1,33 +0,0 @@
name: Enhancement Reopener
on:
schedule:
- cron: 20 12 * * * # Run at 12:20 PM UTC (4:20 AM PST, 5:20 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Reopener
uses: ./.github/actions/Reopener
with:
readonly: ${{ github.event.inputs.readonly }}
alsoApplyToOpenIssues: true
reopenComment: This feature request has received enough votes to be added to our backlog.
labels: enhancement
minimumVotes: 3
ignoreLabels: debugger,internal,Feature Request
milestoneId: 30
milestoneName: Triage
setMilestoneId: 28
removeLabels: more votes needed
@@ -1,28 +0,0 @@
name: External closer - debugger
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: external,debugger
ignoreLabels: language service,internal
closeDays: 0
closeComment: "This issue has been closed because it is external or not applicable to the extension."
@@ -1,32 +0,0 @@
name: Feature Request Closer (no milestone)
on:
schedule:
- cron: 50 11 * * * # Run at 11:50 AM UTC (3:50 AM PST, 4:50 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: Feature Request
ignoreLabels: debugger,internal
addLabels: more votes needed
closeDays: 60
maximumVotes: 2
closeComment: "This feature request is being closed due to insufficient upvotes. Please leave a 👍-upvote or 👎-downvote reaction on the issue to help us prioritize it. When enough upvotes are received, this issue will be eligible for our backlog."
setMilestoneId: 30
ignoreMilestoneNames: "*"
@@ -1,32 +0,0 @@
name: Feature Request Closer (Triage)
on:
schedule:
- cron: 40 11 * * * # Run at 11:40 AM UTC (3:40 AM PST, 4:40 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: Feature Request
ignoreLabels: debugger,internal
addLabels: more votes needed
closeDays: 60
maximumVotes: 2
closeComment: "This feature request is being closed due to insufficient upvotes. Please leave a 👍-upvote or 👎-downvote reaction on the issue to help us prioritize it. When enough upvotes are received, this issue will be eligible for our backlog."
milestoneName: Triage
milestoneId: 30
@@ -1,33 +0,0 @@
name: Feature Request Reopener
on:
schedule:
- cron: 20 12 * * * # Run at 12:20 PM UTC (4:20 AM PST, 5:20 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Reopener
uses: ./.github/actions/Reopener
with:
readonly: ${{ github.event.inputs.readonly }}
alsoApplyToOpenIssues: true
reopenComment: This feature request has received enough votes to be added to our backlog.
labels: Feature Request
minimumVotes: 3
ignoreLabels: debugger,internal
milestoneId: 30
milestoneName: Triage
setMilestoneId: 28
removeLabels: more votes needed
@@ -1,28 +0,0 @@
name: Investigate closer - debugger
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: investigate,debugger
ignoreLabels: language service,internal
closeDays: 180
closeComment: "This issue has been closed as lower priority. We're sorry if this issue still impacts you but unfortunately we're not able to address this. We will accept a pull request from the community if it's applicable for this issue."
@@ -1,28 +0,0 @@
name: Investigate Costing closer - debugger
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: "investigate: costing,debugger"
ignoreLabels: language service,internal
closeDays: 180
closeComment: "This issue has been closed as lower priority. We're sorry if this issue still impacts you but unfortunately we're not able to address this. We will accept a pull request from the community if it's applicable for this issue."
@@ -1,73 +0,0 @@
# Reuable workflow for compiling and testing extension.
name: Compile and test extension
on:
workflow_call:
inputs:
runner-env:
required: true
type: string
platform:
# Expects 'mac', 'linux', or 'windows'
required: true
type: string
yarn-args:
type: string
jobs:
build:
runs-on: ${{ inputs.runner-env }}
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependencies
run: yarn install ${{ inputs.yarn-args }}
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Run unit tests
run: yarn test
working-directory: Extension
# NOTE : We can't run the test that require the native binary files
# yet -- there will be an update soon that allows the tester to
# acquire them on-the-fly
# - name: Run languageServer integration tests
# if: ${{ inputs.platform == 'windows' }}
# run: yarn test --scenario=SingleRootProject
# working-directory: Extension
# - name: Run E2E IntelliSense features tests
# if: ${{ inputs.platform == 'windows' }}
# run: yarn test --scenario=MultirootDeadlockTest
# working-directory: Extension
# NOTE: For mac/linux run the tests with xvfb-action for UI support.
# Another way to start xvfb https://github.com/microsoft/vscode-test/blob/master/sample/azure-pipelines.yml
# - name: Run languageServer integration tests (xvfb)
# if: ${{ inputs.platform == 'mac' || inputs.platform == 'linux' }}
# uses: coactions/setup-xvfb@v1
# with:
# run: yarn test --scenario=SingleRootProject
# working-directory: Extension
# - name: Run E2E IntelliSense features tests (xvfb)
# if: ${{ inputs.platform == 'mac' || inputs.platform == 'linux' }}
# uses: coactions/setup-xvfb@v1
# with:
# run: yarn test --scenario=MultirootDeadlockTest
# working-directory: Extension
-27
View File
@@ -1,27 +0,0 @@
name: Locker
on:
schedule:
- cron: 30 11 * * * # Run at 11:30 AM UTC (3:30 AM PST, 4:30 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Locker
uses: ./.github/actions/Locker
with:
readonly: ${{ github.event.inputs.readonly }}
daysSinceClose: 45
daysSinceUpdate: 3
ignoreLabels: more votes needed,debugger,internal
@@ -1,31 +0,0 @@
name: More Info Needed Closer - debugger
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: more info needed,debugger
ignoreLabels: language service,internal
involves: wardengnaw,pieandcakes,calgagi
closeDays: 14
closeComment: "This issue has been closed because it needs more information and has not had recent activity."
pingDays: 7
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the problem no longer exists, or adding more information."
@@ -1,30 +0,0 @@
name: More Info Needed Closer
on:
schedule:
- cron: 10 11 * * * # Run at 11:10 AM UTC (3:10 AM PST, 4:10 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: more info needed
ignoreLabels: debugger,internal
closeDays: 30
closeComment: "This issue has been closed because it needs more information and has not had recent activity."
pingDays: 14
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the problem no longer exists, or adding more information."
@@ -1,31 +0,0 @@
name: Question Closer - debugger
on:
schedule:
- cron: 20 11 * * * # Run at 11:20 AM UTC (3:20 AM PST, 4:20 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: question,debugger
ignoreLabels: language service,internal
involves: wardengnaw,pieandcakes,calgagi
closeDays: 14
closeComment: "This issue has been closed because it is a question and has not had recent activity."
pingDays: 7
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the question has been answered."
-30
View File
@@ -1,30 +0,0 @@
name: Question Closer
on:
schedule:
- cron: 20 11 * * * # Run at 11:20 AM UTC (3:20 AM PST, 4:20 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
uses: ./.github/actions/StaleCloser
with:
readonly: ${{ github.event.inputs.readonly }}
labels: question
ignoreLabels: debugger,internal
closeDays: 60
closeComment: "This issue has been closed because it is a question and has not had recent activity."
pingDays: 80
pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the question has been answered."
+1 -3
View File
@@ -6,10 +6,8 @@ browse*.db*
*.exe
*.ilk
# ignore exported localization xlf and LCL directories
Build/loc/LCL
# ignore exported localization xlf directory
vscode-extensions-localization-export
OneLocBuild
# ignore imported localization xlf directory
vscode-translations-import
-117
View File
@@ -1,117 +0,0 @@
name: $(date:yyyyMMdd)$(rev:.r)
trigger:
branches:
include:
- main
- release
schedules:
- cron: 30 5 * * 0
branches:
include:
- main
always: true
resources:
repositories:
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
variables:
- name: Codeql.Enabled
value: true
- name: Codeql.Language
value: javascript
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: AzurePipelinesWindows2022compliantGPT
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: AzurePipelinesWindows2022compliantGPT
os: windows
tsa:
enabled: true
config:
tsaVersion: TsaV2
codebase: NewOrUpdate
codebaseName: vscode-cpptools
tsaStamp: $(TsaProjectName)
tsaEnvironment: PROD
notificationAliases: $(TsaNotificationAlias)
codebaseAdmins: $(TsaCodebaseAdmins)
instanceUrl: $(TsaInstanceUrl)
projectName: $(TsaProjectName)
areaPath: $(TsaAreaPath)
iterationPath: $(TsaIterationPath)
alltools: true
repositoryName: vscode-cpptools
policheck:
enabled: true
featureFlags:
autoBaseline: false
stages:
- stage: build
jobs:
- job: Phase_1
displayName: Build cpptools.vsix
timeoutInMinutes: 60
cancelTimeoutInMinutes: 1
templateContext:
outputs:
- output: pipelineArtifact
displayName: 'cpptools.vsix'
condition: succeeded()
targetPath: $(Build.ArtifactStagingDirectory)\Extension
artifactName: cpptools.vsix
steps:
- checkout: self
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
displayName: Use Yarn 1.x
- task: UseNode@1
displayName: Use Node 16.x
inputs:
version: 16.x
- task: CmdLine@2
displayName: Delete .npmrc if it exists
inputs:
script: IF EXIST %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc del %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc
- task: Npm@0
name: NpmInstall_2
displayName: Install vsce
inputs:
arguments: --global @vscode/vsce
- task: CmdLine@1
name: ProcessRunner_11
displayName: Create Extension Staging Directory
inputs:
filename: mkdir
arguments: $(Build.ArtifactStagingDirectory)\Extension
- task: CmdLine@1
name: ProcessRunner_12
displayName: Run VSCE to package vsix
inputs:
filename: vsce
arguments: package --yarn -o $(Build.ArtifactStagingDirectory)\Extension\cpptools.vsix
workingFolder: $(Build.SourcesDirectory)\Extension
- task: Npm@0
displayName: Uninstall vsce
inputs:
command: uninstall
arguments: --global @vscode/vsce
-6
View File
@@ -1,6 +0,0 @@
This folder contains the entitlements needed for the debugger to run on macOS.
We use the entitlements that the .net runtime uses. See https://github.com/dotnet/runtime/blob/57678512d214af368ff055f358c5106f1aa19ac4/eng/pipelines/common/entitlements.plist
Related Links:
https://docs.microsoft.com/en-us/dotnet/core/install/macos-notarization-issues#default-entitlements
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>com.apple.security.task_for_pid-allow</key>
<true/>
</dict>
</plist>
-30
View File
@@ -1,30 +0,0 @@
---
parameters:
archs: ["x86_64", "arm64"]
jobs:
- job:
pool:
name: VSEngSS-MicroBuild2022-1ES
steps:
- checkout: none
- ${{ each arch in parameters.archs }}:
- task: DownloadPipelineArtifact@1
displayName: 'Downloading unsigned_lldb-mi_${{ arch }}'
inputs:
targetPath: '$(Pipeline.Workspace)/Artifacts'
artifactName: 'unsigned_lldb-mi_${{ arch }}'
- task: MicroBuildSignMacFiles@1
displayName: 'ESRP Sign'
inputs:
SigningTarget: '$(Pipeline.Workspace)\Artifacts\lldb-mi_${{ arch }}.zip'
SigningCert: 8023
- task: PublishPipelineArtifact@1
displayName: 'Publish signed LLDB-MI'
inputs:
targetPath: '$(Pipeline.Workspace)\Artifacts\lldb-mi_${{ arch }}.zip'
artifactName: 'lldb-mi_${{ arch }}_zip'
...
-160
View File
@@ -1,160 +0,0 @@
parameters:
# Note: Make sure llvm_repo is the same as the one in Extension/cgmanifest.json
# 'RepositoryUrl' for llvm-project.
llvm_repo: https://github.com/llvm/llvm-project.git
# Note: Make sure llvm_commit is the same as the one in Extension/cgmanifest.json
# 'CommitHash' for llvm-project.
llvm_commit: 0d44201451f03ba907cdb268ddddfc3fa38a0ebd
llvm_build_type: Release
llvm_arch: x86_64
llvm_additional_parameters: "-DLLDB_USE_SYSTEM_DEBUGSERVER=ON -DLLDB_RELOCATABLE_PYTHON=1 -DLLDB_INCLUDE_TESTS=OFF -DLLDB_BUILD_FRAMEWORK=1"
# Note: Make sure lldb_mi_repo is the same as the one in Extension/cgmanifest.json
# 'CommitHash' for lldb-mi.
lldb_mi_repo: https://github.com/lldb-tools/lldb-mi.git
# Note: Make sure lldb_mi_commit is the same as the one in Extension/cgmanifest.json
# 'CommitHash' for lldb-mi.
lldb_mi_commit: 2388bd74133bc21eac59b2e2bf97f2a30770a315
lldb_mi_additional_parameters: "-DUSE_LLDB_FRAMEWORK=1"
jobs:
- job: LLDB_MI_${{ parameters.llvm_arch }}
timeoutInMinutes: 360
pool:
${{if eq(parameters['llvm_arch'], 'arm64')}}:
name: cpptoolsMacM1pool
${{ else }}:
vmImage: macOS-latest
steps:
- task: CmdLine@2
displayName: 'Install Dependencies'
inputs:
script: brew install cmake ninja swig
continueOnError: true
- task: CmdLine@2
displayName: 'Make sure buildspace does not exist'
inputs:
script: rm -rf $(Build.StagingDirectory)/buildspace
condition: always()
- task: CmdLine@2
displayName: 'Build LLVM Project'
inputs:
script: |
log_and_exec_cmd() {
echo "##[command] $1"
$1
}
log_and_exec_cmd "sudo rm -rf /Library/Developer/CommandLineTools"
log_and_exec_cmd "sudo xcode-select --switch /Applications/XCode.app"
log_and_exec_cmd "cd $(Build.StagingDirectory)"
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace"
log_and_exec_cmd "git clone ${{ parameters.llvm_repo }} llvm-project"
log_and_exec_cmd "cd llvm-project"
log_and_exec_cmd "git checkout ${{ parameters.llvm_commit }}"
log_and_exec_cmd "./lldb/scripts/macos-setup-codesign.sh"
log_and_exec_cmd "cd .."
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace/llvm-inst"
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace/llvm-build"
log_and_exec_cmd "cd $(Build.StagingDirectory)/buildspace/llvm-build"
log_and_exec_cmd "cmake -DLLVM_ENABLE_PROJECTS=clang;lldb -DCMAKE_BUILD_TYPE=${{ parameters.llvm_build_type }} -DCMAKE_INSTALL_PREFIX=$(Build.StagingDirectory)/buildspace/llvm-inst/ -DCMAKE_OSX_ARCHITECTURES=${{ parameters.llvm_arch }} ${{ parameters.llvm_additional_parameters }} -GNinja $(Build.StagingDirectory)/llvm-project/llvm"
if [[ $? -ne 0 ]]
then
echo "##[error] cmake llvm failed"
cat $(Build.SourcesDirectory)/buildspace/llvm-build/CMakeFiles/CMakeError.log
exit 1
fi
log_and_exec_cmd ninja
if [[ $? -ne 0 ]]
then
echo "##[error] ninja failed"
exit 1
fi
### Workaround for https://github.com/llvm/llvm-project/issues/108
log_and_exec_cmd "ninja install"
# Remove conflicting LLDB.framework file.
log_and_exec_cmd "rm -rf $(Build.StagingDirectory)/buildspace/llvm-inst/Library/Frameworks/LLDB.framework"
# Build lldb/sources/API first
log_and_exec_cmd "cmake -P $(Build.StagingDirectory)/buildspace/llvm-build/tools/lldb/source/API/cmake_install.cmake"
### End of Workaround
log_and_exec_cmd "ninja install"
if [[ $? -ne 0 ]]
then
echo "##[error] ninja install failed"
exit 1
fi
echo "##[section] Build LLDB-MI"
# Download lldb-mi and build it against our custom installation.
log_and_exec_cmd "cd $(Build.StagingDirectory)/buildspace"
log_and_exec_cmd "git clone ${{ parameters.lldb_mi_repo }} lldb-mi"
log_and_exec_cmd "cd lldb-mi"
log_and_exec_cmd "git checkout ${{ parameters.lldb_mi_commit }}"
# Create a separate build directory for building lldb-mi.
log_and_exec_cmd "mkdir build"
log_and_exec_cmd "cd build"
log_and_exec_cmd "cmake -DCMAKE_PREFIX_PATH=$(Build.StagingDirectory)/buildspace/llvm-inst/ -DCMAKE_OSX_ARCHITECTURES=${{ parameters.llvm_arch }} ${{ parameters.lldb_mi_additional_parameters }} -GNinja .."
log_and_exec_cmd "ninja"
if [[ $? -ne 0 ]]
then
echo "##[error] ninja failed"
exit 1
fi
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/publish"
log_and_exec_cmd "cd $(Build.StagingDirectory)/publish"
log_and_exec_cmd "mkdir -p ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin"
log_and_exec_cmd "cp $(Build.StagingDirectory)/buildspace/lldb-mi/build/src/lldb-mi ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/."
# Set rpath for finding LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath @rpath/LLDB.framework/Versions/A/LLDB ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/lldb-mi"
# Set rpath for App Store XCode LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath /Applications/Xcode.app/Contents/SharedFrameworks/ ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/lldb-mi"
# Set rpath for XCode CLI LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath /Library/Developer/CommandLineTools/Library/PrivateFrameworks/ ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/lldb-mi"
# Set rpath next to the lldb-mi executable LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath @executable_path/. ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/lldb-mi"
# Add entitlements
log_and_exec_cmd "codesign -s - -f --entitlements $(Build.SourcesDirectory)/Build/lldb-mi/debugger-entitlements.plist ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/bin/lldb-mi"
# Grab NOTICE.TXT
cp $(Build.SourcesDirectory)/Build/lldb-mi/NOTICE.TXT ./debugAdapters/lldb-mi_${{ parameters.llvm_arch }}/.
zip -r $(Build.StagingDirectory)/lldb-mi_${{ parameters.llvm_arch }}.zip ./debugAdapters
- task: PublishPipelineArtifact@1
displayName: 'Publish LLDB-MI'
inputs:
targetPath: '$(Build.StagingDirectory)/lldb-mi_${{ parameters.llvm_arch }}.zip'
artifactName: 'unsigned_lldb-mi_${{ parameters.llvm_arch }}'
- task: CmdLine@2
displayName: 'Clean up'
inputs:
script: rm -rf $(Build.StagingDirectory)/buildspace
condition: always()
+123 -21
View File
@@ -1,23 +1,125 @@
parameters:
- name: Build_Type
displayName: Build Type
type: string
default: Release
variables:
llvm_repo: https://github.com/llvm/llvm-project.git
llvm_branch: release/10.x
llvm_build_type: Release
llvm_arch: x86_64
llvm_additional_parameters: "-DLLDB_RELOCATABLE_PYTHON=1 -DLLDB_INCLUDE_TESTS=OFF -DLLDB_BUILD_FRAMEWORK=1"
# TODO: fix lldb_mi_repo and lldb_mi_branch (https://github.com/lldb-tools/lldb-mi/pull/37 and https://github.com/lldb-tools/lldb-mi/pull/39)
lldb_mi_repo: https://github.com/WardenGnaw/lldb-mi # TODO: Change to lldb-tools
lldb_mi_branch: release/cpptools # TODO: Change to master
lldb_mi_additional_parameters: "-DUSE_LLDB_FRAMEWORK=1"
stages:
- stage: Build
dependsOn: []
jobs:
- template: lldb-mi.template.yml
parameters:
llvm_build_type: ${{ parameters.Build_Type }}
llvm_arch: x86_64
- template: lldb-mi.template.yml
parameters:
llvm_build_type: ${{ parameters.Build_Type }}
llvm_arch: arm64
jobs:
- job: LLDB_MI
timeoutInMinutes: 360
pool:
vmImage: 'macOS-latest'
steps:
- task: CmdLine@2
displayName: 'Install Dependencies'
inputs:
script: brew install cmake ninja swig
continueOnError: true
- stage: Signing
dependsOn: ["Build"]
jobs:
- template: lldb-mi-sign.template.yml
- task: CmdLine@2
displayName: 'Build LLVM Project'
inputs:
script: |
log_and_exec_cmd() {
echo "##[command] $1"
$1
}
log_and_exec_cmd "cd $(Build.StagingDirectory)"
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace"
log_and_exec_cmd "git clone $(llvm_repo) llvm-project"
log_and_exec_cmd "cd llvm-project"
log_and_exec_cmd "git checkout $(llvm_branch)"
log_and_exec_cmd "./lldb/scripts/macos-setup-codesign.sh"
log_and_exec_cmd "cd .."
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace/llvm-inst"
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/buildspace/llvm-build"
log_and_exec_cmd "cd $(Build.StagingDirectory)/buildspace/llvm-build"
log_and_exec_cmd "cmake -DLLVM_ENABLE_PROJECTS=clang;lldb -DCMAKE_BUILD_TYPE=$(llvm_build_type) -DCMAKE_INSTALL_PREFIX=$(Build.StagingDirectory)/buildspace/llvm-inst/ -DCMAKE_OSX_ARCHITECTURES=$(llvm_arch) $(llvm_additional_parameters) -GNinja $(Build.StagingDirectory)/llvm-project/llvm"
if [[ $? -ne 0 ]]
then
echo "##[error] cmake llvm failed"
cat $(Build.SourcesDirectory)/buildspace/llvm-build/CMakeFiles/CMakeError.log
exit 1
fi
log_and_exec_cmd ninja
if [[ $? -ne 0 ]]
then
echo "##[error] ninja failed"
exit 1
fi
### Workaround for https://github.com/llvm/llvm-project/issues/108
log_and_exec_cmd "ninja install"
# Remove conflicting LLDB.framework file.
log_and_exec_cmd "rm -rf $(Build.StagingDirectory)/buildspace/llvm-inst/Library/Frameworks/LLDB.framework"
# Build lldb/sources/API first
log_and_exec_cmd "cmake -P $(Build.StagingDirectory)/buildspace/llvm-build/tools/lldb/source/API/cmake_install.cmake"
### End of Workaround
log_and_exec_cmd "ninja install"
if [[ $? -ne 0 ]]
then
echo "##[error] ninja install failed"
exit 1
fi
echo "##[section] Build LLDB-MI"
# Download lldb-mi and build it against our custom installation.
log_and_exec_cmd "cd $(Build.StagingDirectory)/buildspace"
log_and_exec_cmd "git clone $(lldb_mi_repo) lldb-mi"
log_and_exec_cmd "cd lldb-mi"
log_and_exec_cmd "git checkout $(lldb_mi_branch)"
# Create a separate build directory for building lldb-mi.
log_and_exec_cmd "mkdir build"
log_and_exec_cmd "cd build"
log_and_exec_cmd "cmake -DCMAKE_PREFIX_PATH=$(Build.StagingDirectory)/buildspace/llvm-inst/ $(lldb_mi_additional_parameters) -GNinja .."
log_and_exec_cmd "ninja"
if [[ $? -ne 0 ]]
then
echo "##[error] ninja failed"
exit 1
fi
log_and_exec_cmd "mkdir $(Build.StagingDirectory)/publish"
log_and_exec_cmd "cd $(Build.StagingDirectory)/publish"
log_and_exec_cmd "mkdir -p ./debugAdapters/lldb-mi/bin"
log_and_exec_cmd "cp $(Build.StagingDirectory)/buildspace/lldb-mi/build/src/lldb-mi ./debugAdapters/lldb-mi/bin/."
# Set rpath for finding LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath @rpath/LLDB.framework/Versions/A/LLDB ./debugAdapters/lldb-mi/bin/lldb-mi"
# Set rpath for App Store XCode LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath /Applications/Xcode.app/Contents/SharedFrameworks/ ./debugAdapters/lldb-mi/bin/lldb-mi"
# Set rpath for XCode CLI LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath /Library/Developer/CommandLineTools/Library/PrivateFrameworks/ ./debugAdapters/lldb-mi/bin/lldb-mi"
# Set rpath next to the lldb-mi executable LLDB.Framework
log_and_exec_cmd "install_name_tool -add_rpath @executable_path/. ./debugAdapters/lldb-mi/bin/lldb-mi"
# Grab NOTICE.TXT
cp $(Build.SourcesDirectory)/Build/lldb-mi/NOTICE.TXT ./debugAdapters/lldb-mi/.
# Build can be found at https://dev.azure.com/ms/vscode-cpptools/_build?definitionId=313
# Click on the build and select 'Artifacts'
- task: PublishPipelineArtifact@1
displayName: 'Publish LLDB-MI'
inputs:
targetPath: '$(Build.StagingDirectory)/publish'
artifactName: 'lldb-mi'
-14
View File
@@ -1,14 +0,0 @@
{
"Projects": [
{
"LanguangeSet": "VS_Main_Languages",
"LocItems": [
{
"SourceFile": "vscode-extensions-localization-export\\vscode-extensions\\vscode-cpptools.xlf",
"Languages": "cs;de;es;fr;it;ja;ko;pl;pt-BR;ru;tr;zh-Hans;zh-Hant",
"LclFile": "Build\\loc\\LCL\\{Lang}\\vscode-cpptools.xlf.lcl"
}
]
}
]
}
-62
View File
@@ -1,62 +0,0 @@
# ==================================================================================
# Pipeline for VsCodeExtension-Localization build definition
# Runs OneLocBuild task to localize xlf file
# ==================================================================================
resources:
repositories:
- repository: self
clean: true
trigger: none
pr: none
schedules:
- cron: "0 7 * * *"
displayName: Daily 7 AM
branches:
include:
- main
always: true
pool:
name: 'AzurePipelines-EO'
demands:
- ImageOverride -equals AzurePipelinesWindows2022compliant
steps:
- task: NodeTool@0
inputs:
versionSpec: '18.x'
displayName: 'Install Node.js'
- task: CmdLine@2
inputs:
script: 'cd Extension && yarn install'
- task: CmdLine@2
inputs:
script: 'cd ./Extension && yarn run translations-export && cd ..'
- task: OneLocBuild@2
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
locProj: 'Build/loc/LocProject.json'
outDir: '$(Build.ArtifactStagingDirectory)'
isCreatePrSelected: false
prSourceBranchPrefix: 'locfiles'
packageSourceAuth: 'patAuth'
patVariable: '$(OneLocBuildPat)'
LclSource: lclFilesfromPackage
LclPackageId: 'LCL-JUNO-PROD-VCPP'
lsBuildXLocPackageVersion: '7.0.30510'
- task: CmdLine@2
inputs:
script: 'cd Extension && node ./translations_auto_pr.js microsoft vscode-cpptools csigs $(csigsPat) csigs [email protected] "$(Build.ArtifactStagingDirectory)/loc" vscode-extensions-localization-export/vscode-extensions && cd ..'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
+2 -9
View File
@@ -1,10 +1,3 @@
# Microsoft Open Source Code of Conduct
## Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
Resources:
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [[email protected]](mailto:[email protected]) with questions or concerns
- Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support)
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments.
+2 -17
View File
@@ -6,14 +6,14 @@
* File an [issue](https://github.com/Microsoft/vscode-cpptools/issues) and a [pull request](https://github.com/Microsoft/vscode-cpptools/pulls) with the change and we will review it.
* If the change affects functionality, add a line describing the change to [**CHANGELOG.md**](Extension/CHANGELOG.md).
* Try and add a test in [**test/extension.test.ts**](Extension/test/unitTests/extension.test.ts).
* Run tests via opening the [**Extension**](https://github.com/Microsoft/vscode-cpptools/tree/main/Extension) folder in Visual Studio Code, selecting the "Launch Tests" configuration in the Debug pane, and choosing "Start Debugging".
* Run tests via opening the [**Extension**](https://github.com/Microsoft/vscode-cpptools/tree/master/Extension) folder in Visual Studio Code, selecting the "Launch Tests" configuration in the Debug pane, and choosing "Start Debugging".
## About the Code
* Execution starts in the `activate` method in [**main.ts**](Extension/src/main.ts).
* `processRuntimeDependencies` handles the downloading and installation of the OS-dependent files. Downloading code exists in [**packageManager.ts**](Extension/src/packageManager.ts).
* `downloadCpptoolsJsonPkg` handles the **cpptools.json**, which can be used to enable changes to occur mid-update, such as turning the `intelliSenseEngine` to `"Default"` for a certain percentage of users.
* The debugger code is in the [**Debugger**](https://github.com/Microsoft/vscode-cpptools/tree/main/Extension/src/Debugger) folder.
* The debugger code is in the [**Debugger**](https://github.com/Microsoft/vscode-cpptools/tree/master/Extension/src/Debugger) folder.
* [**LanguageServer/client.ts**](Extension/src/LanguageServer/client.ts) handles various language server functionality.
* [**LanguageServer/configurations.ts**](Extension/src/LanguageServer/configurations.ts) handles functionality related to **c_cpp_properties.json**.
* [**telemetry.ts**](Extension/src/telemetry.ts): Telemetry data gets sent to either `logLanguageServerEvent` or `logDebuggerEvent`.
@@ -33,18 +33,3 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle();
const readmeMessage: string = localize("refer.read.me", "Please refer to {0} for troubleshooting information. Issues can be created at {1}", readmePath, "https://github.com/Microsoft/vscode-cpptools/issues");
```
* The first parameter to localize should be a unique key for that string, not used by any other call to localize() in the file unless representing the same string. The second parameter is the string to localize. Both of these parameters must be string literals. Tokens such as {0} and {1} are supported in the localizable string, with replacement values passed as additional parameters to localize().
## Contributor License Agreement
This project welcomes contributions and suggestions. Most contributions require you to
agree to a Contributor License Agreement (CLA) declaring that you have the right to,
and actually do, grant us the rights to use your contribution. For details, visit
https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need
to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
instructions provided by the bot. You will only need to do this once across all repositories using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
+1 -1
View File
@@ -21,4 +21,4 @@ This option will generate a tasks.json file for you, build your active source fi
### F5
Another way to begin building and debugging your active file is to execute the command by pressing <kbd>F5</kbd>. This method will configure
both a tasks.json and launch.json file for you, build your active source file, and then launch the debugger.
both a tasks.json and launch.json file for you, build your active source file, and then launch the debugger.
+1 -1
View File
@@ -1,3 +1,3 @@
# Fib
This code sample is to show debugging. Update `launch.json` and `tasks.json` in the `.vscode` folder to use your setup to build and debug.
This code sample is to show debugging. Update `launch.json` and `tasks.json` in the `.vscode` folder to use your setup to build and debug.
+6 -6
View File
@@ -15,14 +15,14 @@ static int fib(int n){
switch (n) {
case 0: return 1;
case 1: return 1;
default: return (fib(n-2) + fib(n-1));
}
default: return (fib(n-2) + fib(n-1));
}
}
void * thread_proc(void* ctx)
{
int tid = g_tid++;
char thread_name[16];
sprintf(thread_name, "Thread %d", tid);
#ifdef __APPLE__
@@ -30,19 +30,19 @@ void * thread_proc(void* ctx)
#else
pthread_setname_np(pthread_self(), thread_name);
#endif
// Random delay, 0 - 0.5 sec
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500000000 + ((float)rand() / (float)RAND_MAX) * 500000000;
nanosleep(&ts, NULL);
volatile int i = 0;
while (i <= 30) {
std::cout << "Thread " << tid << ": fib(" << i << ") = " << fib(i) << std::endl;
i++;
nanosleep(&ts, NULL);
}
std::cout << thread_name << " exited!" << std::endl;
}
+2 -10
View File
@@ -10,14 +10,6 @@ Prerequisite steps:
* From a command line, run the following commands from the **Extension** folder in the root of the repository:
* `yarn install` will install the dependencies needed to build the extension.
* **(optional)** `yarn global add vsce` will install `vsce` globally to create a VSIX package that you can install.
* **(optional)** Set an environment variable `CPPTOOLS_DEV=1`.
* This enables the local developer workflow when testing the debugger, copying dependencies from the **node_modules** folder. Testing the language server does not require this step.
* Open the **Extension** folder in Visual Studio Code and press F5. This will launch a VS Code Extension Host window and activate the TypeScript debugger. You can set breakpoints on the extension source code and debug your scenario.
* If, after pressing F5, you see the following error in the `[Extension Development Host]` window,
> Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: Missing binary at .../vscode-cpptools/Extension/bin/cpptools
* Then, you can follow the instructions in this [comment in a discussion about building this extension locally](https://github.com/microsoft/vscode-cpptools/discussions/8745#discussioncomment-2091563).
> get the <package.version.number> binaries from installing the extension and then copying the binaries
1. To do this, install this extension from the Visual Studio Marketplace and find its location on your device. It might be in a directory like `\\wsl$\Ubuntu\home\hamir\.vscode-server\extensions\ms-vscode.cpptools-<package.version.number>`, for example.
2. Next, go to the `bin/` directory of the aforementioned directory, and drag-and-drop, or copy-and-paste, `cpptools` and `cpptools-srv` from `...\extensions\ms-vscode.cpptools-<package.version.number>\bin\` to this repository's `Extension\bin\` directory on your local device, so that `.../vscode-cpptools/Extension/bin/cpptools` and `.../vscode-cpptools/Extension/bin/cpptools-srv` both exist in your workspace.
3. The aforementioned warning should be gone, and Intellisense, which gives those squiggly red error lines, should now be present.
4. The `insiders` branch has binaries compatible with the latest Pre-Release version of the extension, and the `release` branch has binaries compatible with the latest Release version, but the `main` branch may have TypeScript changes that are incompatible with the published binaries, in which case, you'll need to create a branch off the `insiders` or `release` branches.
* Feel free to use [the Discussions tab of this repository](https://github.com/microsoft/vscode-cpptools/discussions) if you have any further questions on building this extension locally.
@@ -1,20 +0,0 @@
# Exception Settings
The Microsoft Windows C/C++ debugger (cppvsdbg) supports configuration options for if the debugger stops when exceptions are thrown. This is done with the 'All Exceptions' check box in the BREAKPOINTS section of the 'Run and Debug' view.
Note that the BREAKPOINTS section will be missing this entry until the first time that the folder has been debugged with the 'cppvsdbg' debugger.
Checking 'All Exceptions' will configure the debugger to stop when an exception is thrown.
##### Exception Conditions
The 'All Exceptions' checkbox support conditions to break on only selected exception types (C++ exceptions) or codes (Win32 exceptions). To edit the condition, click on the pencil icon or right click on the entry and invoke 'Edit Condition'. The condition is a comma-separated list of exception types and codes to break on, or if the list starts with '!', a list of exception types and codes to ignore.
Examples conditions:
| Example condition value | Result |
|-------------------------|--------|
| 0xC0000005, 0xC0000094 | Break on Win32 Access Violation exceptions and integer division by zero exceptions |
| std::out_of_range, 0xC0000005 | This will break on out-of-range exceptions, and access violation exceptions |
| !MyExceptionClass | This will break on all exceptions except C++ `MyExceptionClass` exceptions |
| !MyExceptionClass, 0x6831C815 | This will break on all exceptions except C++ `MyExceptionClass` exceptions and Win32 exceptions with custom code 0x6831C815 |
@@ -1,6 +1,6 @@
# How To Debug MIEngine
MIEngine is one of the components used to enable the C/C++ debugging scenario with the Microsoft C/C++ extension with VS Code. This document is to help enable users who want to debug and contribute to MIEngine to fix issues or extend functionality. MIEngine is used to communicate with `gdb`/`lldb` using the MI protocol.
MIEngine is one of the components used to enable the C/C++ debugging scenario with the Microsoft C/C++ extension with VS Code. This document is to help enable users who want to debug and contribute to MIEngine to fix issues or extend functionality. MIEngine is used to communicate with `gdb`/`lldb` using the MI protocol.
**Repository:** https://github.com/Microsoft/MIEngine
@@ -19,7 +19,7 @@ You can open the solution file **MIDebugEngine.sln** located under **src** and c
The symbol files are as follows:
**On Windows**
**On Windows**
* Microsoft.MICore.pdb
* Microsoft.MIDebugEngine.pdb
* vscode\OpenDebugAD7.pdb
@@ -37,7 +37,7 @@ On Windows, the easiest way to debug is to use Visual Studio. Locate the **src\D
If you are not building the extension, Locate the **out\src\Debugger\extension.ts** file in the **.vscode\extensions\ms-vscode.cpptools** folder and open it in an editor.
Locate the following lines:
Locate the following lines:
```json
return {
command: command
@@ -48,13 +48,13 @@ and add the following line to the object:
args: ["--pauseForDebugger"]
```
This will cause the debugger to look like it has hung once you start debugging, but in reality it is waiting for a debugger to attach. Set your breakpoints and attach your debugger to the `OpenDebugAD7.exe` process. Once the debugger is attached, VS Code should start debugging and you can reproduce your scenario.
This will cause the debugger to look like it has hung once you start debugging, but in reality it is waiting for a debugger to attach. Set your breakpoints and attach your debugger to the `OpenDebugAD7.exe` process. Once the debugger is attached, VS Code should start debugging and you can reproduce your scenario.
### Debugging MIEngine running on Linux or macOS
### Debugging MIEngine running on Linux or Mac OS X
#### With MonoDevelop
On Linux and macOS, we use `mono` as our framework. You can download Xamarin Studio v5.10.1.6 and remotely attach to your Mac or Linux box to debug there.
On Linux and Mac OS X, we use `mono` as our framework. You can download Xamarin Studio v5.10.1.6 and remotely attach to your Mac or Linux box to debug there.
##### Install Prerequisites
1. Install [GTK](http://www.mono-project.com/download/).
@@ -78,12 +78,12 @@ MonoDevelop.exe
##### Configure the extension to enable remote debugging
Open the **~/.vscode/extensions/ms-vscode.cpptools-\<version\>/debugAdapters/OpenDebugAD7** file with a text editor and locate and uncomment the line at the bottom. When you start debugging, it will now hang until the remote debugger is attached from Xamarin Studio.
Open the **~/.vscode/extensions/ms-vscode.cpptools-\<version\>/debugAdapters/OpenDebugAD7** file with a text editor and locate and uncomment the line at the bottom. When you start debugging, it will now hang until the remote debugger is attached from Xamarin Studio.
##### Attach the remote debugger
In MonoDevelop: Run -> Run With -> Custom Command Mono Soft Debugger.
Fill in the IP and port of the Linux/macOS machine and hit "Connect" to start debugging.
Fill in the IP and port of the Linux/Mac OS X machine and hit "Connect" to start debugging.
After you've done this once, you can hit the MonoDevelop "Play" button or <kbd>F5</kbd> to bring up the connect dialog again.
@@ -113,7 +113,7 @@ After you've done this once, you can hit the MonoDevelop "Play" button or <kbd>F
##### Configure the extension to enable remote debugging
Open the **~/.vscode/extensions/ms-vscode.cpptools-\<version\>/debugAdapters/OpenDebugAD7** file with a text editor and locate and uncomment the line at the bottom. When you start debugging, it will now hang until the remote debugger is attached from VS Code.
Open the **~/.vscode/extensions/ms-vscode.cpptools-\<version\>/debugAdapters/OpenDebugAD7** file with a text editor and locate and uncomment the line at the bottom. When you start debugging, it will now hang until the remote debugger is attached from VS Code.
##### Attach the remote debugger
+16 -16
View File
@@ -240,7 +240,7 @@
</xs:annotation>
</xs:attribute>
</xs:complexType>
<!-- Attributes for elements that support filtering by view-->
<xs:attributeGroup name="ViewConstraints">
<xs:attribute name="IncludeView" type ="ViewIncludeType" use="optional" />
@@ -335,9 +335,9 @@
are evaluated in the context of the node.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attribute>
</xs:attributeGroup>
<xs:complexType name="ListItemsNodeType">
<xs:annotation>
<xs:documentation>Expression that points to value of the linked list node. It can be left empty or have 'this' to refer to the linked list node itself. This expression is evaluated under the context of the linked list node and not the parent linked list type.</xs:documentation>
@@ -402,7 +402,7 @@
<xs:documentation>
Indicates that the item should use the icon associated with general data.
</xs:documentation>
</xs:annotation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Method">
<xs:annotation>
@@ -864,16 +864,16 @@
<xs:complexType name="MostDerivedObjectType">
<xs:annotation>
<xs:documentation>
Specifies an expression which evaluates to the current object, casted to its most-derived type.
In most cases, the debugger is able to automatically determine an object's most-derived type, in which case use of the &lt;MostDerivedType&gt;
Specifies an expression which evaluates to the current object, casted to its most-derived type.
In most cases, the debugger is able to automatically determine an object's most-derived type, in which case use of the &lt;MostDerivedType&gt;
element is unecessary. Automatic determination of an object's most-derived type requires the object to be an instance of a C++ class, with a
compiler-generated virtual function table. This is sufficient for most class-hierarchies; however, custom logic may occasionally be necessary
when dealing with a class hierarchy that does not contain virtual functions, or when the virtual function table is manually constructed by the
when dealing with a class hierarchy that does not contain virtual functions, or when the virtual function table is manually constructed by the
application code.
</xs:documentation>
</xs:annotation>
<xs:simpleContent>
<xs:extension base="StringType">
<xs:attributeGroup ref="CommonAttributes" />
@@ -935,12 +935,12 @@
<xs:annotation>
<xs:documentation>
Indicates that the given type is a smart pointer. The text inside this element specifies the expression to evaluate the underlying pointer.
The &lt;SmartPointer&gt; element has the following effects:
- If no alternative &lt;DisplayString&gt; element is provided (or all &lt;DisplayString&gt; elements have failed conditions), the underlying pointer will be the display string
- If no alternative &lt;StringView&gt; element is provided (or all &lt;StringView&gt; elements have failed conditions), the underlying pointer will be the string view, if it has one.
- If no alternative &lt;Expand&gt; element is provided, the expansion of the smart pointer will be the expansion of the underlying pointer.
- The smart pointer class will also support overloaded operators as determined by the &lt;Usage&gt; attribute. You can opt out of this behavior by specifying
- The smart pointer class will also support overloaded operators as determined by the &lt;Usage&gt; attribute. You can opt out of this behavior by specifying
'DefaultExpansion=&quot;false&quot;'
</xs:documentation>
</xs:annotation>
@@ -949,7 +949,7 @@
<xs:attributeGroup ref="CommonAttributes_NoCondition" />
<xs:attribute name="Usage" type="SmartPointerUsage" use="required">
<xs:annotation>
<xs:documentation>Indicates which combinations of operators this smart pointer object supports.
<xs:documentation>Indicates which combinations of operators this smart pointer object supports.
</xs:documentation>
</xs:annotation>
</xs:attribute>
@@ -1004,10 +1004,10 @@
<xs:documentation>Specifies an optional priority to assign to this entry for type matching. Higher priority entries within a particular file or directory
are checked first. &lt;Type&gt; entries that do not specify a priority receive default priority of &quot;Medium&quot; &lt;AlternativeType&gt; entries which do not specify a priority
will inherit the priority of the enclosing &lt;Type&gt; element. The priority is only used to disambiguate type matching when all other means of disambiguation are unavailable.
For example, entries with more specific template instantiations, module constraints, or view constraints will take priority regardless of any priority values specified.
Similarly, regardless of priority, natvis files that are part of a loaded project will always take precedence over files in the user natvis directory,
which will, in turn, take precedence over files in the system-wide natvis directory.
For example, entries with more specific template instantiations, module constraints, or view constraints will take priority regardless of any priority values specified.
Similarly, regardless of priority, natvis files that are part of a loaded project will always take precedence over files in the user natvis directory,
which will, in turn, take precedence over files in the system-wide natvis directory.
If two entries have the same priority and cannot otherwise be disambiguated, it is unspecified which one will get used.
</xs:documentation>
</xs:annotation>
+4 -4
View File
@@ -1,4 +1,4 @@
*.js
dist/
vscode*.d.ts
gulpfile.js
test/**/index.ts
test/**/runTest.ts
tools/prepublish.js
+53 -72
View File
@@ -1,9 +1,4 @@
module.exports = {
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/strict",
],
"env": {
"browser": true,
"es6": true,
@@ -11,41 +6,21 @@ module.exports = {
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json", ".scripts/tsconfig.json"],
"ecmaVersion": 2022,
"sourceType": "module",
"warnOnUnsupportedTypeScriptVersion": false,
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"@typescript-eslint/tslint",
"eslint-plugin-jsdoc",
"@typescript-eslint/eslint-plugin",
"@typescript-eslint/eslint-plugin-tslint",
"eslint-plugin-import",
"eslint-plugin-header"
],
"rules": {
"indent": [
"warn",
4,
{
"SwitchCase": 1,
"ObjectExpression": "first"
}
],
"@typescript-eslint/indent": [
"error", 4
],
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"camelcase": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "typeLike",
"format": ["PascalCase"]
}
],
"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/indent": "error",
"@typescript-eslint/member-delimiter-style": [
"error",
{
@@ -59,20 +34,7 @@ module.exports = {
}
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-extraneous-class": "off",
"no-case-declarations": "off",
"no-useless-escape": "off",
"no-floating-decimal": "error",
"keyword-spacing": ["error", { "before": true, "overrides": { "this": { "before": false } } }],
"arrow-spacing": ["error", { "before": true, "after": true }],
"semi-spacing": ["error", { "before": false, "after": true }],
"no-extra-parens": ["error", "all", { "nestedBinaryExpressions": false, "ternaryOperandBinaryExpressions": false }],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
@@ -86,16 +48,8 @@ module.exports = {
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/method-signature-style": ["error", "method"],
"@typescript-eslint/space-infix-ops": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"arrow-body-style": "error",
"comma-dangle": "error",
"comma-spacing": "off",
"@typescript-eslint/comma-spacing": "error",
"constructor-super": "error",
"curly": "error",
"eol-last": "error",
@@ -117,19 +71,17 @@ module.exports = {
"no-fallthrough": "error",
"no-invalid-this": "error",
"no-irregular-whitespace": "error",
"rest-spread-spacing": ["error", "never"],
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
"no-multiple-empty-lines": "error",
"no-new-wrappers": "error",
"no-redeclare": "error",
"no-return-await": "error",
"no-sequences": "error",
"no-sparse-arrays": "error",
"no-trailing-spaces": "error",
"no-multi-spaces": "error",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"space-before-blocks": "error",
"no-var": "error",
"one-var": [
"error",
@@ -142,25 +94,54 @@ module.exports = {
"never"
],
"spaced-comment": [
"off",
"always",
{ "line": { "exceptions": ["/"] } } // triple slash directives
"error",
"always"
],
"use-isnan": "error",
"valid-typeof": "error",
"yoda": "error",
"space-infix-ops": "error",
"header/header": [
"warn",
"block",
[
" --------------------------------------------------------------------------------------------",
" * Copyright (c) Microsoft Corporation. All Rights Reserved.",
" * See 'LICENSE' in the project root for license information.",
" * ------------------------------------------------------------------------------------------ "
],
],
"@typescript-eslint/tslint/config": [
"error",
{
"rules": {
"encoding": true,
"file-header": [
true,
".*"
],
"import-spacing": true,
"match-default-export-name": true,
"no-boolean-literal-compare": true,
"no-mergeable-namespace": true,
"no-reference-import": true,
"no-unnecessary-callback-wrapper": true,
"number-literal-format": true,
"one-line": [
true,
"check-catch",
"check-finally",
"check-else",
"check-open-brace",
"check-whitespace"
],
"prefer-method-signature": true,
"prefer-while": true,
"typedef": [
true,
"variable-declaration",
"call-signature",
"variable-declaration-ignore-function"
],
"whitespace": [
true,
"check-branch",
"check-operator",
"check-separator",
"check-preblock",
"check-type"
]
}
}
]
}
};
+2 -4
View File
@@ -1,7 +1,7 @@
# ignore dependency packages
node_modules
# ignore compiled typescript
# ignore compliled typescript
out
dist
@@ -12,7 +12,6 @@ LLVM
bin/cpptools*
bin/*.dll
bin/.vs
bin/LICENSE.txt
# ignore lock files
install.lock
@@ -25,6 +24,7 @@ install.lock
# ignore generated localization file
**/nls.*.json
**/*.nls.json
**/*.nls.*.json
# ignore generate native header
@@ -33,5 +33,3 @@ localized_string_ids.h
# ignore generate files. It will be generated when building
src/nativeStrings.ts
vscode*.d.ts
.scripts/_*
-64
View File
@@ -1,64 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { error } from 'node:console';
import { resolve, sep } from 'node:path';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { verbose } from '../src/Utility/Text/streams';
import { $root, Git, brightGreen, cyan, getModifiedIgnoredFiles, rimraf } from './common';
// notes:
// list all gitignore'd files that are modified: `git clean -Xd -n`
// list all untracked and ignored files that are modified/created: `git clean -Xd -n`
export async function main() {
await rimraf(resolve($root, 'dist'));
}
export async function all() {
await rimraf(...(await getModifiedIgnoredFiles()).filter(each => !each.includes('node_modules')));
}
export async function reset() {
verbose(`Resetting all .gitignored files in extension`);
await rimraf(...await getModifiedIgnoredFiles());
}
async function details(files: string[]) {
let all = await Promise.all(files.filter(each => each).map(async (each) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [filename, stats ] = await filepath.stats(each);
return {
filename: stats.isDirectory() ? cyan(`${each}${sep}**`) : brightGreen(`${each}`),
date: stats.mtime.toLocaleDateString().replace(/\b(\d)\//g, '0$1\/'),
time: stats.mtime.toLocaleTimeString().replace(/^(\d)\:/g, '0$1:'),
modified: stats.mtime
};
}));
all = all.sort((a, b) => a.modified.getTime() - b.modified.getTime());
// print a formatted table so the date and time are aligned
const max = all.reduce((max, each) => Math.max(max, each.filename.length), 0);
all.forEach(each => console.log(` ${each.filename.padEnd(max)} [${each.date} ${each.time}]`));
console.log('');
}
export async function show(opt?: string) {
switch (opt?.toLowerCase()) {
case 'new':
console.log(cyan('\n\nNew files:'));
const r = await Git('ls-files', '--others', '--exclude-standard', '-z');
return details(r.stdio.all().map(each => resolve(each.trim().replace(/\0/g, ''))));
case undefined:
case '':
case 'ignored':
case 'untracked':
console.log(cyan('\n\nUntracked+Ignored files:'));
return details(await getModifiedIgnoredFiles());
default:
return error(`Unknown option '${opt}'`);
}
}
-40
View File
@@ -1,40 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { spawnSync } from 'child_process';
import { verbose } from '../src/Utility/Text/streams';
import { $args, $root, $scenario, assertAnyFile, brightGreen, gray, green, pwd } from './common';
import { resolve } from 'path';
import { getTestInfo } from '../test/common/selectTests';
import { install, options } from "./vscode";
export { install, reset } from './vscode';
export async function main() {
let ti = await getTestInfo($scenario);
if (!ti) {
// try using the first arg as a scenario name or location
ti = await getTestInfo($args[0], $args[0] ? resolve(pwd, $args[0]) : undefined);
if (ti) {
$args[0] = ti.workspace;
}
} else {
// we found it
$args.unshift(ti.workspace);
}
await assertAnyFile('dist/src/main.js', `The extension entry point '${$root}/dist/src/main.js is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const { cli, args } = await install();
// example of installing an extension into code
//verbose(`Installing release version of 'ms-vscode.cpptools'`);
//spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cpptools'], { encoding: 'utf-8', stdio: 'ignore' })
verbose(green('Launch VSCode'));
const ARGS = [...args, ...options.launchArgs.filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir=')), `--extensionDevelopmentPath=${$root}`, ...$args ];
verbose(gray(`${cli}\n ${ [...ARGS ].join('\n ')}`));
spawnSync(cli, ARGS, { encoding: 'utf-8', stdio: 'ignore', env: { ...process.env, DONT_PROMPT_WSL_INSTALL:"1" } });
}
-343
View File
@@ -1,343 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { Command, CommandFunction } from '../src/Utility/Process/program';
import { ok } from 'assert';
import { CommentJSONValue, parse, stringify } from 'comment-json';
import { mkdir as md, readFile, rm, writeFile } from 'fs/promises';
import { IOptions, glob as globSync } from 'glob';
import { dirname, resolve } from 'path';
import { chdir, cwd, env } from 'process';
import { setImmediate } from 'timers/promises';
import { promisify } from 'util';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { is } from '../src/Utility/System/guards';
import { verbose } from '../src/Utility/Text/streams';
export const $root = resolve(`${__dirname}/..`);
export let $cmd = 'main';
export let $scenario = '';
// loop through the args and pick out --scenario=... and remove it from the $args and set $scenario
process.argv.slice(2).filter(each => !(each.startsWith('--scenario=') && ($scenario = each.substring('--scenario='.length))));
export const $args = process.argv.slice(2).filter(each => !each.startsWith('--'));
export const $switches = process.argv.slice(2).filter(each => each.startsWith('--'));
/** enqueue the call to the callback function to happen on the next available tick, and return a promise to the result */
export function then<T>(callback: () => Promise<T> | T): Promise<T> {
return setImmediate().then(callback);
}
export const pwd = env.INIT_CWD ?? cwd();
verbose(yellow(`pwd: ${pwd}`));
// ensure we're in the extension folder.
chdir($root);
// dump unhandled async errors to the console and exit.
process.on('unhandledRejection', (reason: any, _promise) => {
error(`${reason?.stack?.split(/\r?\n/).filter(l => !l.includes('node:internal') && !l.includes('node_modules')).join('\n')}`);
process.exit(1);
});
const git = new Command('git');
export const Git = async (...args: Parameters<Awaited<CommandFunction>>) => (await git)(...args);
export const GitClean = async (...args: Parameters<Awaited<CommandFunction>>) => (await new Command(await git, 'clean'))(...args);
export async function getModifiedIgnoredFiles() {
const {code, error, stdio } = await GitClean('-Xd', '-n');
if (code) {
throw new Error(`\n${error.all().join('\n')}`);
}
// return the full path of files that would be removed.
return Promise.all(stdio.filter("Would remove").map((s) => filepath.exists(s.replace(/^Would remove /, ''), $root)).filter(p => p));
}
export async function rimraf(...paths: string[]) {
const all = [];
for (const each of paths) {
if (!each) {
continue;
}
if (await filepath.isFolder(each)) {
verbose(`Removing folder ${red(each)}`);
all.push(rm(each, {recursive: true, force: true}));
continue;
}
verbose(`Removing file ${red(each)}`);
all.push(rm(each, {force: true}));
}
await Promise.all(all);
}
export async function mkdir(filePath: string) {
const [fullPath, info] = await filepath.stats(filePath, $root);
if (info) {
if (info.isDirectory()) {
return fullPath;
}
throw new Error(`Cannot create directory '${filePath}' because there is a file there.`);
}
await md(fullPath, { recursive: true });
return fullPath;
}
export const glob: (pattern: string, options?: IOptions) => Promise<string[]> = promisify(globSync);
export async function write(filePath: string, data: Buffer | string) {
await mkdir(dirname(filePath));
if (await filepath.isFile(filePath)) {
const content = await readFile(filePath);
if (is.string(data)) {
// if we're passed a text file, we should match the line endings of the existing file.
const textContent = content.toString();
// normalize the line endings to the same as the current file.
data = textContent.indexOf('\r\n') > -1 ? data.replace(/\r\n|\n/g, '\r\n') : data.replace(/\r\n|\n/g, '\n');
// if the text content is a match, we don't have to change anything
if (textContent === data) {
verbose(`Text file at '${filePath}' is up to date.`);
return;
}
} else {
// if the binary content is a match, we don't have to change anything
if (content.equals(data)) {
verbose(`File at '${filePath}' is up to date.`);
return;
}
}
}
verbose(`Writing file '${filePath}'`);
await writeFile(filePath, data);
}
export async function updateFiles(files: string[], dest: string | Promise<string>) {
const target = is.promise(dest) ? await dest : dest;
await Promise.all(files.map(async (each) => {
const sourceFile = await filepath.isFile(each, $root);
if (sourceFile) {
const targetFile = resolve(target, each);
await write(targetFile, await readFile(sourceFile));
}
}));
}
export async function go() {
if (require.main) {
// loop through the args and pick out the first non --arg and remove it from the $args and set $cmd
for (let i = 0; i < $args.length; i++) {
const each = $args[i];
if (!each.startsWith('--') && require.main.exports[each]) {
$cmd = each;
$args.splice(i, 1);
break;
}
}
verbose(`${yellow("Running task:")} ${green($cmd)} ${green($args.join(' '))}`);
require.main.exports[$cmd](...$args);
}
}
void then(go);
export async function read(filename: string) {
const content = await readFile(filename);
ok(content, `File '${filename}' has no content`);
return content.toString();
}
export async function readJson(filename: string, fallback = {}): Promise<CommentJSONValue> {
try {
return parse(await read(filename));
} catch {
return fallback as CommentJSONValue;
}
}
export async function writeJson(filename: string, object: CommentJSONValue) {
await write(filename, stringify(object, null, 4));
}
export function error(text: string) {
console.error(`\n${red('ERROR')}: ${text}`);
return true;
}
export function warn(text: string) {
console.error(`\n${yellow('WARNING')}: ${text}`);
return true;
}
export function note(text: string) {
console.error(`\n${cyan('NOTE')}: ${text}`);
}
export function underline(text: string) {
return `\u001b[4m${text}\u001b[0m`;
}
export function bold(text: string) {
return `\u001b[1m${text}\u001b[0m`;
}
export function dim(text: string) {
return `\u001b[2m${text}\u001b[0m`;
}
export function brightGreen(text: string) {
return `\u001b[38;2;19;161;14m${text}\u001b[0m`;
}
export function green(text: string) {
return `\u001b[38;2;78;154;6m${text}\u001b[0m`;
}
export function brightWhite(text: string) {
return `\u001b[38;2;238;238;236m${text}\u001b[0m`;
}
export function gray(text: string) {
return `\u001b[38;2;117;113;94m${text}\u001b[0m`;
}
export function yellow(text: string) {
return `\u001b[38;2;252;233;79m${text}\u001b[0m`;
}
export function red(text: string) {
return `\u001b[38;2;197;15;31m${text}\u001b[0m`;
}
export function cyan(text: string) {
return `\u001b[38;2;0;174;239m${text}\u001b[0m`;
}
export const hr = "===============================================================================";
export function heading(text: string, level = 1) {
switch (level) {
case 1:
return `${underline(bold(text))}`;
case 2:
return `${brightGreen(text)}`;
case 3:
return `${green(text)}`;
}
return `${bold(text)}\n`;
}
export function optional(text: string) {
return gray(text);
}
export function cmdSwitch(text: string) {
return optional(`--${text}`);
}
export function command(text: string) {
return brightWhite(bold(text));
}
export function hint(text: string) {
return green(dim(text));
}
export function count(num: number) {
return gray(`${num}`);
}
export function position(text: string) {
return gray(`${text}`);
}
export async function assertAnyFolder(oneOrMoreFolders: string | string[], errorMessage?: string): Promise<string> {
oneOrMoreFolders = is.array(oneOrMoreFolders) ? oneOrMoreFolders : [oneOrMoreFolders];
for (const each of oneOrMoreFolders) {
const result = await filepath.isFolder(each, $root);
if (result) {
verbose(`Folder ${brightGreen(each)} exists.`);
return result;
}
}
if (errorMessage) {
if (!$switches.includes('--quiet')) {
error(errorMessage);
}
process.exit(1);
}
}
export async function assertAnyFile(oneOrMoreFiles: string | string[], errorMessage?: string): Promise<string> {
oneOrMoreFiles = is.array(oneOrMoreFiles) ? oneOrMoreFiles : [oneOrMoreFiles];
for (const each of oneOrMoreFiles) {
const result = await filepath.isFile(each, $root);
if (result) {
verbose(`Folder ${brightGreen(each)} exists.`);
return result;
}
}
if (errorMessage) {
if (!$switches.includes('--quiet')) {
error(errorMessage);
}
process.exit(1);
}
}
const quiet = process.argv.includes('--quiet');
export async function checkPrep() {
let failing = false;
failing = !await assertAnyFolder('dist/test') && (quiet || warn(`The compiled test files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/walkthrough') && (quiet || warn(`The walkthrough files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/html') && (quiet || warn(`The html files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/schema') && (quiet || warn(`The schema files are not in place.`)) || failing;
failing = !await assertAnyFile('dist/nls.metadata.json') && (quiet || warn(`The extension translation file '${$root}/dist/nls.metadata.json is missing.`)) || failing;
failing = await checkDTS() || failing;
if (!failing) {
verbose('Prep files appear to be in place.');
}
return failing;
}
export async function checkCompiled() {
let failing = false;
failing = await checkDTS() || failing;
failing = !await assertAnyFile('dist/src/main.js') && (quiet || warn(`The extension entry point '${$root}/dist/src/main.js is missing.`)) || failing;
if (!failing) {
verbose('Compiled files appear to be in place.');
}
return failing;
}
export async function checkDTS() {
let failing = false;
failing = !await assertAnyFile('vscode.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.d.ts is missing.`)) || failing;
failing = !await assertAnyFile('vscode.proposed.terminalDataWriteEvent.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.proposed.terminalDataWriteEvent.d.ts is missing.`)) || failing;
if (!failing) {
verbose('VSCode d.ts files appear to be in place.');
}
return failing;
}
export async function checkBinaries() {
let failing = false;
failing = !await assertAnyFile(['bin/cpptools.exe', 'bin/cpptools']) && (quiet || warn(`The native binary files are not present. You should either build or install the native binaries\n\n.`)) || failing;
if (!failing) {
verbose('Native binary files appear to be in place.');
}
return failing;
}
-28
View File
@@ -1,28 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { watch as watchFiles } from 'fs/promises';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { verbose } from '../src/Utility/Text/streams';
import { $root, glob, mkdir, updateFiles } from './common';
export async function main() {
verbose(`Copying walkthrough media to extension/dist folder`);
await updateFiles(await glob('walkthrough/images/**/*'), mkdir('dist'));
}
export async function watch() {
const source = await filepath.isFolder('walkthrough/images', $root);
if (source) {
verbose(`Watching ${source} folder for changes.`);
console.log('Press Ctrl+C to exit.');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const event of watchFiles(source, {recursive: true })) {
await main();
}
}
}
-134
View File
@@ -1,134 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { parse } from 'comment-json';
import { resolve } from 'path';
import { read, write } from './common';
// ****************************
// Command: generate-native-strings
// The following is used to generate nativeStrings.ts and localized_string_ids.h from ./src/nativeStrings.json
// If adding localized strings to the native side, start by adding it to nativeStrings.json and use this to generate the others.
// ****************************
export async function main() {
const $root = resolve(`${__dirname}/..`);
const stringTable = parse(await read(`${$root}/src/nativeStrings.json`)) as any;
let nativeEnumContent = "";
let nativeStringTableContent = "";
let typeScriptSwitchContent = "";
let stringIndex = 1;
for (const property in stringTable) {
let stringValue = stringTable[property];
let hintValue;
if (typeof stringValue !== "string") {
hintValue = stringValue.hint;
stringValue = stringValue.text;
}
// Add to native enum
nativeEnumContent += ` ${property} = ${stringIndex},\n`;
// Add to native string table
nativeStringTableContent += ` ${JSON.stringify(stringValue)},\n`;
// Add to TypeScript switch
// Skip empty strings, which can be used to prevent enum/index reordering
if (stringValue !== "") {
// It's possible that a translation may skip "{#}" entries, so check for up to 50 of them.
let numArgs = 0;
for (let i = 0; i < 50; i++) {
if (stringValue.includes(`{${i}}`)) {
numArgs = i + 1;
}
}
typeScriptSwitchContent += ` case ${stringIndex}:\n`;
if (numArgs !== 0) {
typeScriptSwitchContent += ` if (stringArgs) {\n`;
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
for (let i = 0; i < numArgs; i++) {
typeScriptSwitchContent += `, stringArgs[${i}]`;
}
typeScriptSwitchContent += `);\n break;\n }\n`;
}
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
typeScriptSwitchContent += `);\n break;\n`;
}
++stringIndex;
}
// --------------------------------------------------------------------------------------------
// Generate the TypeScript file
// --------------------------------------------------------------------------------------------
const typeScriptContent = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
'use strict';
import * as nls from 'vscode-nls';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export const localizedStringCount: number = ${stringIndex};
export function lookupString(stringId: number, stringArgs?: string[]): string {
let message: string = "";
switch (stringId) {
case 0:
// Special case for blank string
break;
${typeScriptSwitchContent}
default:
console.assert(\"Unrecognized string ID\");
break;
}
return message;
}
`;
// If the file isn't there, or the contents are different, write it out
await write(`${$root}/src/nativeStrings.ts`, typeScriptContent);
// --------------------------------------------------------------------------------------------
// Generate the native string header file
// --------------------------------------------------------------------------------------------
const nativeContents = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
#pragma once
// NOLINTBEGIN(modernize-raw-string-literal)
enum class localized_string_id : unsigned int
{
blank = 0,
${nativeEnumContent}};
inline static const char *localizable_strings[] = {
"",
${nativeStringTableContent}};
// NOLINTEND(modernize-raw-string-literal)
`;
// If the file isn't there, or the contents are different, write it out
await write(`${$root}/localized_string_ids.h`, nativeContents);
}
-95
View File
@@ -1,95 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as fs from "fs";
import * as path from 'path';
import { parseString } from 'xml2js';
import { mkdir, write } from './common';
export async function main() {
const localizeRepoPath = process.argv[2];
const cpptoolsRepoPath = process.argv[3];
if (!localizeRepoPath || !cpptoolsRepoPath) {
console.error(`ERROR: Usage: ${path.parse(process.argv[0]).base} ${path.parse(process.argv[1]).base} <Localize repo path> <vscode-cpptools repo path>`);
return;
}
console.log("Importing EDGE strings from Localize repo: " + localizeRepoPath);
console.log("Writing to cpptools repo: " + cpptoolsRepoPath);
if (!fs.existsSync(path.join(localizeRepoPath, ".git"))) {
console.error("ERROR: Localize repo submodule is not initialized in Localize repo");
return;
}
const languages = [
{ id: "zh-tw", folderName: "cht", transifexId: "zh-hant" },
{ id: "zh-cn", folderName: "chs", transifexId: "zh-hans" },
{ id: "fr", folderName: "fra" },
{ id: "de", folderName: "deu" },
{ id: "it", folderName: "ita" },
{ id: "es", folderName: "esn" },
{ id: "ja", folderName: "jpn" },
{ id: "ko", folderName: "kor" },
{ id: "ru", folderName: "rus" },
{ id: "bg", folderName: "bul" }, // VS Code supports Bulgarian, but VS is not currently localized for those languages.
{ id: "hu", folderName: "hun" }, // VS Code supports Hungarian, but VS is not currently localized for those languages.
{ id: "pt-br", folderName: "ptb", transifexId: "pt-BR" },
{ id: "tr", folderName: "trk" },
{ id: "cs", folderName: "csy" },
{ id: "pl", folderName: "plk" }
];
const locFolderNames = fs.readdirSync(localizeRepoPath).filter(f => fs.lstatSync(path.join(localizeRepoPath, f)).isDirectory());
for (const locFolderName of locFolderNames) {
const lclPath = path.join(localizeRepoPath, locFolderName, "vc/vc/cpfeui.dll.lcl");
const languageInfo = languages.find(l => l.folderName === locFolderName);
if (!languageInfo) {
return;
}
const languageId = languageInfo.id;
const outputLanguageFolder = path.join(cpptoolsRepoPath, "Extension/bin/messages", languageId);
const outputPath = path.join(outputLanguageFolder, "messages.json");
const sourceContent = fs.readFileSync(lclPath, 'utf-8');
// Scan once, just to determine how many there are the size of the array we need
let highestValue = 0;
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId === ";String Table") {
item.Item.forEach((subItem) => {
const itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
const resultArray = new Array(highestValue);
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId === ";String Table") {
item.Item.forEach((subItem) => {
const itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
resultArray[itemId] = subItem.Str[0].Tgt[0].Val[0].replace(/\]5D;/g, "]");
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
await mkdir(outputLanguageFolder);
await write(outputPath, JSON.stringify(resultArray, null, 4) + "\n");
}
}
-17
View File
@@ -1,17 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { gray, green, readJson } from './common';
export async function main() {
const pkg = await readJson('package.json') as Record<string, any>;
if (pkg.scripts) {
console.log(green('\n\nAvailable script commands:\n'));
for (const key of Object.keys(pkg.scripts)) {
console.log(green(`yarn ${key} - ${gray(pkg.scripts[key])}`));
}
console.log('');
}
}
-236
View File
@@ -1,236 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { runTests } from '@vscode/test-electron';
import { spawnSync } from 'child_process';
import { CommentArray, CommentObject } from 'comment-json';
import { readdir } from 'fs/promises';
import { resolve } from 'path';
import { env } from 'process';
import { returns } from '../src/Utility/Async/returns';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { is } from '../src/Utility/System/guards';
import { verbose } from '../src/Utility/Text/streams';
import { getTestInfo } from '../test/common/selectTests';
import { $args, $root, $scenario, assertAnyFile, assertAnyFolder, brightGreen, checkBinaries, cmdSwitch, cyan, error, gray, green, readJson, red, writeJson } from './common';
import { install, isolated, options } from './vscode';
export { install, reset } from './vscode';
const sowrite = process.stdout.write.bind(process.stdout) as (...args: unknown[]) => boolean;
const sewrite = process.stderr.write.bind(process.stderr) as (...args: unknown[]) => boolean;
const filters = [
/^\[(.*)\].*/,
/^Unexpected token A/,
/Cannot register 'cmake.cmakePath'/,
/\[DEP0005\] DeprecationWarning/,
/--trace-deprecation/,
/Iconv-lite warning/,
/^Extension '/,
/^Found existing install/
];
// remove unwanted messages from stdio
function filterStdio() {
process.stdout.write = function (...args: unknown[]) {
if (typeof args[0] === 'string') {
const text = args[0];
if (filters.some(each => text.match(each))) {
return true;
}
}
if (args[0] instanceof Buffer) {
const text = args[0].toString();
if (filters.some(each => text.match(each))) {
return true;
}
}
return sowrite(...args);
};
process.stderr.write = function (...args: unknown[]) {
if (typeof args[0] === 'string') {
const text = args[0];
if (filters.some(each => text.match(each))) {
return true;
}
}
if (args[0] instanceof Buffer) {
const text = args[0].toString();
if (filters.some(each => text.match(each))) {
return true;
}
}
return sewrite(...args);
};
}
filterStdio();
async function unitTests() {
await assertAnyFolder('dist/test/unit', `The folder '${$root}/dist/test/unit is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const mocha = await assertAnyFile(["node_modules/.bin/mocha.cmd", "node_modules/.bin/mocha"], `Can't find the mocha testrunner. You might need to run ${brightGreen("yarn install")}\n\n`);
const result = spawnSync(mocha, [`${$root}/dist/test/unit/**/*.test.js`, '--timeout', '30000'], { stdio:'inherit'});
verbose(`\n${green("NOTE:")} If you want to run a scenario test (end-to-end) use ${cmdSwitch('scenario=<NAME>')} \n\n`);
return result.status;
}
async function scenarioTests(assets: string, name: string, workspace: string) {
if (await checkBinaries()) {
process.exit(1);
}
return runTests({
...options,
extensionDevelopmentPath: $root,
extensionTestsPath: resolve($root, 'dist/test/common/selectTests'),
launchArgs: workspace ? [...options.launchArgs, workspace] : options.launchArgs,
extensionTestsEnv: {
SCENARIO: assets
}
});
}
export async function main() {
await assertAnyFolder('dist/test/', `The folder '${$root}/dist/test is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const arg = $args.find(each => !each.startsWith("--"));
const specifiedScenario = $scenario || env.SCENARIO || await getScenarioFolder(arg);
const testInfo = await getTestInfo(specifiedScenario);
if (!testInfo) {
if (arg) {
return error(`Could not find scenario ${arg}`);
}
// lets just run the unit tests
process.exit(await unitTests());
}
// at this point, we're going to run some vscode tests
if (!await filepath.isFolder(isolated)) {
await install();
}
process.exit(await scenarioTests(testInfo.assets, testInfo.name, testInfo.workspace));
}
export async function all() {
if (await checkBinaries()) {
process.exit(1);
}
const finished: string[] = [];
if (await unitTests() !== 0) {
console.log(`${cyan(" UNIT TESTS: ")}${red("failed")}`);
process.exit(1);
}
finished.push(`${cyan(" UNIT TESTS: ")}${green("success")}`);
// at this point, we're going to run some vscode tests
if (!await filepath.isFolder(isolated)) {
await install();
}
try {
const scenarios = await getScenarioNames();
for (const each of scenarios) {
if (await filepath.isFolder(`${$root}/test/scenarios/${each}/tests`)) {
const ti = await getTestInfo(each);
if (ti) {
console.log(`\n\nRunning scenario ${each}`);
const result = await scenarioTests(ti.assets, ti.name, ti.workspace);
if (result) {
console.log(finished.join('\n'));
console.log(` ${cyan(`${ti.name} Tests:`)}${red("failed")}`);
process.exit(result);
}
finished.push(` ${cyan(`${ti.name} Tests:`)}${green("success")}`);
}
}
}
} catch (e) {
error(e);
} finally {
console.log(finished.join('\n'));
}
}
interface Input {
id: string;
type: string;
description: string;
options: CommentArray<{label: string; value: string}>;
}
export async function getScenarioNames() {
return (await readdir(`${$root}/test/scenarios`).catch(returns.none)).filter(each => each !== 'Debugger');
}
export async function getScenarioFolder(scenarioName: string) {
return scenarioName ? resolve(`${$root}/test/scenarios/${(await getScenarioNames()).find(each => each.toLowerCase() === scenarioName.toLowerCase())}`) : undefined;
}
export async function list() {
console.log(`\n${cyan("Scenarios: ")}\n`);
const names = await getScenarioNames();
const max = names.reduce((max, each) => Math.max(max, each), 0);
for (const each of names) {
console.log(` ${green(each.padEnd(max))}: ${gray(await getScenarioFolder(each))}`);
}
}
export async function regen() {
// update the .vscode/launch.json file with the scenarios
const scenarios = await getScenarioNames();
const launch = await readJson(`${$root}/.vscode/launch.json`) as CommentObject;
if (!is.object(launch)) {
return error(`The file ${$root}/.vscode/launch.json is not valid json`);
}
if (!is.array(launch.inputs)) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'inputs' array`);
}
const inputs = launch.inputs as unknown as CommentArray<Input>;
const pickScenario = inputs.find(each => each.id === 'pickScenario');
if (!pickScenario) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'pickScenario' input`);
}
const pickWorkspace = inputs.find(each => each.id === 'pickWorkspace');
if (!pickWorkspace) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'pickWorkspace' input`);
}
for (const scenarioFolder of scenarios) {
const prefix = $root.replace(/\\/g, '/');
if (await filepath.isFolder(`${$root}/test/scenarios/${scenarioFolder}/tests`)) {
const testInfo = await getTestInfo(scenarioFolder);
if (testInfo) {
const label = `${scenarioFolder} `;
const value = testInfo.workspace.replace(/\\/g, '/').replace(prefix, '${workspaceFolder}');
const scenario = pickScenario.options.find(s => s.label === label);
if (!scenario) {
console.log(`Adding scenario ${green(scenarioFolder)} to pickScenario`);
pickScenario.options.push({ label, value });
} else {
verbose(`Skipping scenario ${scenarioFolder} because it already exists`);
}
const wrkspace = pickWorkspace.options.find(s => s.label === label);
if (!wrkspace) {
console.log(`Adding workspace ${green(scenarioFolder)} to pickWorkspace`);
pickWorkspace.options.push({ label, value });
} else {
verbose(`Skipping workspace ${scenarioFolder} because it already exists`);
}
} else {
verbose(`Skipping scenario ${scenarioFolder} because it doesn't look like there are any tests. (maybe try and run ${brightGreen("yarn compile")})`);
}
}
}
await writeJson(`${$root}/.vscode/launch.json`, launch);
}
-12
View File
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "node16",
"moduleResolution": "node16",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"esModuleInterop": true
}
}
-52
View File
@@ -1,52 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { checkBinaries, checkCompiled, checkDTS, checkPrep, error, green } from './common';
const quiet = process.argv.includes('--quiet');
export async function main() {
let failing = await checkPrep() && (quiet || error(`Files are not up to date. Run ${green('yarn prep')} to fix it.`));
failing = (await checkCompiled() && (quiet || error(`Compiled files are not present. Run ${green('yarn compile')} to fix it.`))) || failing;
failing = (await checkBinaries() && (quiet || error(`The native binary files are not present. You should either build or install the native binaries\n\n.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function compiled() {
let failing = false;
failing = (await checkCompiled() && (quiet || error(`Compiled files are not present. Run ${green('yarn compile')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function binaries() {
let failing = false;
failing = (await checkBinaries() && (quiet || error(`The native binary files are not present. You should either build or install the native binaries\n\n.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function prep() {
let failing = false;
failing = (await checkPrep() && (quiet || error(`Files are not up to date. Run ${green('yarn prep')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function dts() {
let failing = false;
failing = (await checkDTS() && (quiet || error(`VSCode import files are not present. Run ${green('yarn prep')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
-61
View File
@@ -1,61 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath } from '@vscode/test-electron';
import { createHash } from 'crypto';
import { tmpdir } from 'os';
import { resolve } from 'path';
import { verbose } from '../src/Utility/Text/streams';
import { mkdir, readJson, rimraf, write } from './common';
export const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(__dirname).digest('hex').substring(0, 6));
export const extensionsDir = resolve(isolated, 'extensions');
export const userDir = resolve(isolated, 'user-data');
export const settings = resolve(userDir, "User", 'settings.json');
export const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${extensionsDir}`, `--user-data-dir=${userDir}`, '--disable-workspace-trust']
};
export async function install() {
try {
// Create a new isolated directory for VS Code instance in the test folder, and make it specific to the extension folder so we can avoid collisions.
// keeping this out of the Extension folder means we're not worried about VS Code getting weird with locking files and such.
verbose(`Isolated VSCode test folder: ${isolated}`);
await mkdir(isolated);
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
args.push(`--extensions-dir=${extensionsDir}`, `--user-data-dir=${userDir}`);
// install the appropriate extensions
// spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cpptools'], { encoding: 'utf-8', stdio: 'ignore' });
// spawnSync(cli, [...args, '--install-extension', 'twxs.cmake'], { encoding: 'utf-8', stdio: 'ignore' });
// spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cmake-tools'], { encoding: 'utf-8', stdio: 'ignore' });
const settingsJson = await readJson(settings, {});
if (!settingsJson["workbench.colorTheme"]) {
settingsJson["workbench.colorTheme"] = "Tomorrow Night Blue";
}
settingsJson["git.openRepositoryInParentFolders"] = "never";
await write(settings, JSON.stringify(settingsJson, null, 4));
return {
cli, args
};
} catch (err: unknown) {
console.log(err);
}
}
export async function reset() {
verbose(`Removing VSCode test folder: ${isolated}`);
await rimraf(isolated);
}
+134 -141
View File
@@ -1,143 +1,136 @@
// A launch configuration that compiles the extension and then opens it inside a new window
{
"version": "0.1.0",
"configurations": [
{
// debugs the extension
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-workspace-trust",
"--extensionDevelopmentPath=${workspaceFolder}",
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**"
],
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
// debugs the extension (selecting the workspace)
"name": "Run Extension-Select Workspace",
"type": "extensionHost",
"request": "launch",
"args": [
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-workspace-trust",
"--extensionDevelopmentPath=${workspaceFolder}",
"${input:pickWorkspace}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**"
],
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
// debug scenario tests (selecting the workspace)
"name": "VSCode Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"env": {
"SCENARIO": "${input:pickScenario}"
},
"args": [
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/dist/test/common/selectTests",
"--scenario=${input:pickScenario}",
"${input:pickScenario}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**"
],
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
// used for debugging unit tests
"name": "MochaTest",
"type": "node",
"request": "attach",
"port": 9229,
"continueOnAttach": true,
"autoAttachChildProcesses": false,
"skipFiles": [
"<node_internals>/**"
],
"outFiles": [
"${workspaceFolder}/dist/**",
"!**/node_modules/**"
]
}
],
"inputs": [
{
"type": "pickString",
"id": "pickScenario",
"description": "Select which scenario to debug VSCode tests.",
"options": [
{
"label": "MultirootDeadlockTest ",
"value": "${workspaceFolder}/test/scenarios/MultirootDeadlockTest/assets/test.code-workspace"
},
{
"label": "SimpleCppProject ",
"value": "${workspaceFolder}/test/scenarios/SimpleCppProject/assets/simpleCppProject.code-workspace"
},
{
"label": "SingleRootProject ",
"value": "${workspaceFolder}/test/scenarios/SingleRootProject/assets/"
},
{
"label": "CompilerDetection ",
"value": "${workspaceFolder}/test/scenarios/CompilerDetection/assets"
}
]
},
{
"type": "pickString",
"id": "pickWorkspace",
"description": "Select which workspace scenario to debug VSCode.",
"default": "-n",
"options": [
{
"label": "(Debug with new window) ",
"value": "-n"
},
{
"label": "MultirootDeadlockTest ",
"value": "${workspaceFolder}/test/scenarios/MultirootDeadlockTest/assets/test.code-workspace"
},
{
"label": "SimpleCppProject ",
"value": "${workspaceFolder}/test/scenarios/SimpleCppProject/assets/simpleCppProject.code-workspace"
},
{
"label": "SingleRootProject ",
"value": "${workspaceFolder}/test/scenarios/SingleRootProject/assets/"
},
{
"label": "CompilerDetection ",
"value": "${workspaceFolder}/test/scenarios/CompilerDetection/assets"
}
]
}
]
}
"version": "0.1.0",
"configurations": [
{
"name": "Launch Extension (development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev",
},
{
"name": "Launch Extension (production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile",
},
{
"name": "Launch Extension (do not build)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
},
{
"name": "Launch Extension (watch, development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev Watch",
},
{
"name": "Launch Extension (watch, production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile Watch",
},
{
"name": "Launch Unit Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/unitTests/index"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Launch Integration Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/test/integrationTests/testAssets/SimpleCppProject",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/languageServer/index"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest",
},
{
"name": "Launch E2E IntelliSense features tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"C:/git/Vcls-vscode-test/SingleRootProject",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/IntelliSenseFeatures/index"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Node Attach",
"type": "node",
"request": "attach",
"port": 5858
},
]
}
+8 -65
View File
@@ -1,67 +1,10 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
"typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
// if you install the mocha test explorer extension, you can run the unit tests from the test explorer UI
"testExplorer.useNativeTesting": true,
"mochaExplorer.files": "./**/unit/**/*.test.js",
"mochaExplorer.watch": "./**/unit/**/*.test.js",
"mochaExplorer.ignore": [
"**/*skip*",
"**/dist/test/**/*.d.ts",
"**/node_modules/**"
],
"mochaExplorer.debuggerConfig": "MochaTest",
"mochaExplorer.logpanel": true,
"mochaExplorer.timeout": 500000,
"mochaExplorer.require": [
"source-map-support/register"
],
"mochaExplorer.monkeyPatch": true,
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.json-language-features",
"editor.tabSize": 4,
"files.insertFinalNewline": true
},
"[jsonc]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.json-language-features",
"editor.tabSize": 4,
"files.insertFinalNewline": true
},
"[typescript]": {
"editor.tabSize": 4,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
"files.insertFinalNewline": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit"
},
},
"eslint.format.enable": true,
"[javascript]": {
"editor.tabSize": 4,
},
"markdown.extension.list.indentationSize": "inherit",
"markdown.extension.toc.levels": "2..6",
"[markdown]": {
"editor.tabSize": 4,
},
"eslint.workingDirectories": [
{
"changeProcessCWD": true,
"directory": "./",
},
{
"changeProcessCWD": true,
"directory": "./.scripts",
}
],
}
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
}
+157 -10
View File
@@ -4,25 +4,172 @@
"version": "2.0.0",
"tasks": [
{
"label": "compile",
"type": "npm",
"script": "compile",
"problemMatcher": "$tsc",
"label": "TypeScript Compile",
"group": {
"kind": "build",
"isDefault": true
}
},
"isBackground": false,
"type": "shell",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared"
},
"command": "yarn",
"args": [
"run",
"compile",
"--loglevel",
"silent"
]
},
{
"label": "watch",
"type": "npm",
"script": "watch",
"label": "TypeScript Lint",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"lint"
],
"problemMatcher": {
"fileLocation": "absolute",
"source": "lint",
"pattern": [
{
"regexp": "(ERROR:) ([a-zA-Z/:\\-\\.]*)\\[(\\d+), (\\d+)\\]: (.*)",
"severity": 1,
"file": 2,
"line": 3,
"column": 4,
"message": 5
}
]
},
"dependsOn": [
"Compile Dev"
]
},
{
"label": "Compile Dev",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"compile-dev"
]
},
{
"label": "Pretest",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"pretest"
],
"dependsOn": [
"Compile Dev"
]
},
{
"label": "TypeScript Compile Watch",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": true,
"problemMatcher": "$tsc-watch",
"type": "shell",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared"
},
"command": "yarn",
"args": [
"run",
"compile-watch",
"--loglevel",
"silent"
],
"problemMatcher": [
{
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
"file": 1,
"line": 2,
"column": 3
},
{
"regexp": "\\s*TS\\d+:\\s*(.*)",
"message": 1
}
],
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "Compilation (.*?)starting…"
},
"endsPattern": {
"regexp": "Compilation (.*?)finished"
}
}
}
]
},
{
"label": "Compile Dev Watch",
"group": "build",
"isBackground": true,
"type": "shell",
"command": "yarn",
"args": [
"run",
"compile-dev-watch"
],
"problemMatcher": [
{
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
"file": 1,
"line": 2,
"column": 3
},
{
"regexp": "\\s*TS\\d+:\\s*(.*)",
"message": 1
}
],
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "Compilation (.*?)starting…"
},
"endsPattern": {
"regexp": "Compilation (.*?)finished"
}
}
}
]
}
]
}
}
+43 -54
View File
@@ -1,54 +1,43 @@
# ignore vscode settings for extension development
.vscode/**
# ignore binaries
obj/**
# ignore source files
tools/**
notices/**
test/**
src/**
# ignore .js files that are webpacked or only used for development
out/src/**
out/tools/**
# don't include the local code and tests compiled files
dist/test/**
# no project scripts
.scripts/**
# ignore ts files in ui
ui/*.ts
# ignore Azure-Pipelines files
jobs/**
cgmanifest.json
# ignore development files
tsconfig.json
test.tsconfig.json
ui.tsconfig.json
tslint.json
.eslintrc.js
webpack.config.js
tscCompileList.txt
gulpfile.js
.gitattributes
.gitignore
CMakeLists.txt
debugAdapters/install.lock*
typings/**
**/*.map
import_edge_strings.js
localized_string_ids.h
translations_auto_pr.js
# ignore i18n language files
i18n/**
# ignore node_modules
node_modules/
# ignore vscode settings for extension development
.vscode/**
# ignore binaries
obj/**
# ignore source files
tools/**
notices/**
test/**
src/**
# ignore .js files that are webpacked or only used for development
out/src/**
out/tools/**
# ignore ts files in ui
ui/*.ts
# ignore Azure-Pipelines files
jobs/**
# ignore development files
tsconfig.json
test.tsconfig.json
tslint.json
.eslintrc.js
webpack.config.js
tscCompileList.txt
gulpfile.js
.gitattributes
.gitignore
CMakeLists.txt
debugAdapters/install.lock*
typings/**
**/*.map
import_edge_strings.js
localized_string_ids.h
translations_auto_pr.js
# ignore i18n language files
i18n/**
-7
View File
@@ -1,7 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
ignore-engines true
disable-self-update-check true
--run.silent true
+35 -1229
View File
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
MICROSOFT PRE-RELEASE SOFTWARE LICENSE TERMS
MICROSOFT C/C++ EXTENSION FOR VISUAL STUDIO CODE
These license terms are an agreement between Microsoft Corporation (or
based on where you live, one of its affiliates) and you. They apply to
the pre-release software named above. The terms also apply to any
Microsoft services or updates for the software, except to the extent
those have additional terms.
IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW.
1. INSTALLATION AND USE RIGHTS. You may only use the C/C++ Extension
for Visual Studio Code with Visual Studio Code, Visual Studio or
Xamarin Studio software to help you develop and test your
applications.
2. TERMS FOR SPECIFIC COMPONENTS
a. Third Party Components. The software may include third party
components with separate legal notices or governed by other
agreements, as may be described in the ThirdPartyNotices file(s)
accompanying the software.
b. Package Managers. The software may include package managers, like
Nuget, that give you the option to download other Microsoft and third
party software packages to use with your application. Those packages
are under their own licenses, and not this agreement. Microsoft does
not distribute, license or provide any warranties for any of the third
party packages.
3. DATA.
a. Data Collection. The software may collect information about you and
your use of the software, and send that to Microsoft. Microsoft may
use this information to provide services and improve our products and
services. You may opt-out of many of these scenarios, but not all, as
described in the product documentation. There are also some features
in the software that may enable you and Microsoft to collect data from
users of your applications. If you use these features, you must comply
with applicable law, including providing appropriate notices to users
of your applications together with a copy of Microsofts privacy
statement. Our privacy statement is located at
https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more
about data collection and use in the help documentation and our
privacy statement. Your use of the software operates as your consent
to these practices.
b. Processing of Personal Data. To the extent Microsoft is a processor
or subprocessor of personal data in connection with the software,
Microsoft makes the commitments in the European Union General Data
Protection Regulation Terms of the Online Services Terms to all
customers effective May 25, 2018, at
http://go.microsoft.com/?linkid=9840733.
4. PRE-RELEASE SOFTWARE. This software is a pre-release version. It
may not work the way a final version of the software will. We may
change it for the final, commercial version. We also may not release a
commercial version.
5. FEEDBACK. If you give feedback about the software to Microsoft, you
give to Microsoft, without charge, the right to use, share and
commercialize your feedback in any way and for any purpose. You will
not give feedback that is subject to a license that requires Microsoft
to license its software or documentation to third parties because we
include your feedback in them. These rights survive this agreement.
6. SCOPE OF LICENSE. The software is licensed, not sold. This
agreement only gives you some rights to use the software. Microsoft
reserves all other rights. Unless applicable law gives you more rights
despite this limitation, you may use the software only as expressly
permitted in this agreement. In doing so, you must comply with any
technical limitations in the software that only allow you to use it in
certain ways. You may not
* work around any technical limitations in the software;
* reverse engineer, decompile or disassemble the software, or attempt
to derive the source code for the software, except and to the extent
required by third party licensing terms governing use of certain open
source components that may be included with the software;
* remove, minimize, block or modify any notices of Microsoft or its
suppliers in the software;
* use the software in any way that is against the law; or
* share, publish, rent, or lease the software, or provide the software
as a stand-alone hosted solution for others to use.
7. EXPORT RESTRICTIONS. You must comply with all domestic and
international export laws and regulations that apply to the software,
which include restrictions on destinations, end users and end use.
For further information on export restrictions, visit
(aka.ms/exporting).
8. SUPPORT SERVICES. Because this software is “as is,” we may not
provide support services for it.
9. ENTIRE AGREEMENT. This agreement, and the terms for supplements,
updates, Internet-based services and support services that you use,
are the entire agreement for the software and support services.
10. APPLICABLE LAW. If you acquired the software in the United
States, Washington law applies to interpretation of and claims for
breach of this agreement, and the laws of the state where you live
apply to all other claims. If you acquired the software in any other
country, its laws apply.
11. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes
certain legal rights. You may have other rights, including consumer
rights, under the laws of your state or country. Separate and apart
from your relationship with Microsoft, you may also have rights with
respect to the party from which you acquired the software. This
agreement does not change those other rights if the laws of your state
or country do not permit it to do so. For example, if you acquired the
software in one of the below regions, or mandatory country law
applies, then the following provisions apply to you:
a. Australia. You have statutory guarantees under the Australian
Consumer Law and nothing in this agreement is intended to affect those
rights.
b. Canada. If you acquired this software in Canada, you may stop
receiving updates by turning off the automatic update feature,
disconnecting your device from the Internet (if and when you re-
connect to the Internet, however, the software will resume checking
for and installing updates), or uninstalling the software. The product
documentation, if any, may also specify how to turn off updates for
your specific device or software.
c. Germany and Austria.
(i) Warranty. The properly licensed software will perform
substantially as described in any Microsoft materials that accompany
the software. However, Microsoft gives no contractual guarantee in
relation to the licensed software.
(ii) Limitation of Liability. In case of intentional conduct, gross
negligence, claims based on the Product Liability Act, as well as, in
case of death or personal or physical injury, Microsoft is liable
according to the statutory law.
Subject to the foregoing clause (ii), Microsoft will only be liable
for slight negligence if Microsoft is in breach of such material
contractual obligations, the fulfillment of which facilitate the due
performance of this agreement, the breach of which would endanger the
purpose of this agreement and the compliance with which a party may
constantly trust in (so-called "cardinal obligations"). In other cases
of slight negligence, Microsoft will not be liable for slight
negligence.
12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU
BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES,
GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL
LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
13. LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM
MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU
CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST
PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
This limitation applies to (a) anything related to the software,
services, content (including code) on third party Internet sites, or
third party applications; and (b) claims for breach of contract,
breach of warranty, guarantee or condition, strict liability,
negligence, or other tort to the extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the
possibility of the damages. The above limitation or exclusion may not
apply to you because your country may not allow the exclusion or
limitation of incidental, consequential or other damages.
Please note: As this software is distributed in Quebec, Canada, some
of the clauses in this agreement are provided below in French.
Remarque : Ce logiciel étant distribué au Québec, Canada, certaines
des clauses dans ce contrat sont fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert
« tel quel ». Toute utilisation de ce logiciel est à votre seule
risque et péril. Microsoft naccorde aucune autre garantie
expresse. Vous pouvez bénéficier de droits additionnels en vertu du
droit local sur la protection des consommateurs, que ce contrat ne
peut modifier. La ou elles sont permises par le droit locale, les
garanties implicites de qualité marchande, dadéquation à un
usage particulier et dabsence de contrefaçon sont exclues.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ
POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses
fournisseurs une indemnisation en cas de dommages directs uniquement
à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune
indemnisation pour les autres dommages, y compris les dommages
spéciaux, indirects ou accessoires et pertes de bénéfices.
Cette limitation concerne:
* tout ce qui est relié au logiciel, aux services ou au contenu (y
compris le code) figurant sur des sites Internet tiers ou dans des
programmes tiers ; et
* les réclamations au titre de violation de contrat ou de garantie,
ou au titre de responsabilité stricte, de négligence ou dune
autre faute dans la limite autorisée par la loi en vigueur.
Elle sapplique également, même si Microsoft connaissait ou
devrait connaître l’éventualité dun tel dommage. Si votre pays
nautorise pas lexclusion ou la limitation de responsabilité
pour les dommages indirects, accessoires ou de quelque nature que ce
soit, il se peut que la limitation ou lexclusion ci-dessus ne
sappliquera pas à votre égard.
EFFET JURIDIQUE. Le présent contrat décrit certains droits
juridiques. Vous pourriez avoir dautres droits prévus par les lois
de votre pays. Le présent contrat ne modifie pas les droits que vous
confèrent les lois de votre pays si celles-ci ne le permettent pas.
+17 -24
View File
@@ -1,33 +1,13 @@
# C/C++ for Visual Studio Code
#### [Repository](https://github.com/microsoft/vscode-cpptools)&nbsp;&nbsp;|&nbsp;&nbsp;[Issues](https://github.com/microsoft/vscode-cpptools/issues)&nbsp;&nbsp;|&nbsp;&nbsp;[Documentation](https://code.visualstudio.com/docs/languages/cpp)&nbsp;&nbsp;|&nbsp;&nbsp;[Code Samples](https://github.com/microsoft/vscode-cpptools/tree/main/Code%20Samples)
#### [Repository](https://github.com/microsoft/vscode-cpptools)&nbsp;&nbsp;|&nbsp;&nbsp;[Issues](https://github.com/microsoft/vscode-cpptools/issues)&nbsp;&nbsp;|&nbsp;&nbsp;[Documentation](https://code.visualstudio.com/docs/languages/cpp)&nbsp;&nbsp;|&nbsp;&nbsp;[Code Samples](https://github.com/microsoft/vscode-cpptools/tree/master/Code%20Samples)&nbsp;&nbsp;|&nbsp;&nbsp;[Offline Installers](https://github.com/microsoft/vscode-cpptools/releases)
[![Badge](https://aka.ms/vsls-badge)](https://aka.ms/vsls)
The C/C++ extension adds language support for C/C++ to Visual Studio Code, including [editing (IntelliSense)](https://code.visualstudio.com/docs/cpp/cpp-ide) and [debugging](https://code.visualstudio.com/docs/cpp/cpp-debug) features.
## Pre-requisites
C++ is a compiled language meaning your program's source code must be translated (compiled) before it can be run on your computer. VS Code is first and foremost an editor, and relies on command-line tools to do much of the development workflow. The C/C++ extension **does not include a C++ compiler or debugger**. You will need to install these tools or use those already installed on your computer.
* C++ compiler pre-installed
* C++ debugger pre-installed
<br/>
Here is a list of compilers and architectures per platform officially supported by the extension. These are reflected by the available [IntelliSense modes](https://code.visualstudio.com/docs/cpp/configure-intellisense-crosscompilation#_intellisense-mode) from the extension's IntelliSense configuration. Note that support for other compilers may be limited.
Platform | Compilers | Architectures
:--- | :--- | :---
Windows | MSVC, Clang, GCC | x64, x86, arm64, arm
Linux | Clang, GCC | x64, x86, arm64, arm
macOS | Clang, GCC | x64, x86, arm64
For more information about installing the required tools or setting up the extension, please follow the tutorials below.
<br/>
<br/>
This preview release of the C/C++ extension adds language support for C/C++ to Visual Studio Code, including features such as IntelliSense and debugging.
## Overview and tutorials
* [C/C++ extension overview](https://code.visualstudio.com/docs/languages/cpp)
* [Introductory Videos](https://code.visualstudio.com/docs/cpp/introvideos-cpp)
C/C++ extension tutorials per compiler and platform
* [Microsoft C++ compiler (MSVC) on Windows](https://code.visualstudio.com/docs/cpp/config-msvc)
@@ -37,7 +17,7 @@ C/C++ extension tutorials per compiler and platform
* [Clang on macOS](https://code.visualstudio.com/docs/cpp/config-clang-mac)
## Quick links
* [Editing features (IntelliSense)](https://code.visualstudio.com/docs/cpp/cpp-ide)
* [Editing features (IntelliSense)](https://code.visualstudio.com/docs/cpp/cpp-ide)
* [IntelliSense configuration](https://code.visualstudio.com/docs/cpp/customize-default-settings-cpp)
* [Enhanced colorization](https://code.visualstudio.com/docs/cpp/colorization-cpp)
* [Debugging](https://code.visualstudio.com/docs/cpp/cpp-debug)
@@ -65,6 +45,19 @@ If someone has already filed an issue that encompasses your feedback, please lea
<br>
Let us know what you think of the extension by taking the quick survey.
## Offline installation
The extension has platform-specific binary dependencies, therefore installation via the Marketplace requires an Internet connection in order to download additional dependencies. If you are working on a computer that does not have access to the Internet or is behind a strict firewall, you may need to use our platform-specific packages and install them by running VS Code's `"Install from VSIX..."` command. These "offline' packages are available at: https://github.com/Microsoft/vscode-cpptools/releases.
Package | Platform
:--- | :---
`cpptools-linux.vsix` | Linux 64-bit
`cpptools-linux-armhf.vsix` | Linux ARM
`cpptools-linux-aarch64.vsix` | Linux ARM 64-bit
`cpptools-osx.vsix` | macOS
`cpptools-win32.vsix` | Windows 64-bit & 32-bit
`cpptools-linux32.vsix` | Linux 32-bit ([available up to version 0.27.0](https://github.com/microsoft/vscode-cpptools/issues/5346))
## Contribution
Contributions are always welcome. Please see our [contributing guide](CONTRIBUTING.md) for more details.
@@ -75,4 +68,4 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
## Data and telemetry
This extension collects usage data and sends it to Microsoft to help improve our products and services. Collection of telemetry is controlled via the same setting provided by Visual Studio Code: `"telemetry.enableTelemetry"`. Read our [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more.
This extension collects usage data and sends it to Microsoft to help improve our products and services. Collection of telemetry is controlled via the same setting provided by Visual Studio Code: `"telemetry.enableTelemetry"`. Read our [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more.
-32
View File
@@ -1,32 +0,0 @@
<h1 data-loc-id="incompatible.extension.heading">Incompatible or Mismatched C/C++ Extension Binaries</h1>
<p data-loc-id="incompat.extension.text1">The C/C++ extension includes native binaries.</p>
<p data-loc-id="incompat.extension.text2">When installed via the marketplace UI in VS Code, the correct native binaries should be included. If incompatible binaries were detected and the C/C++ extension had been installed via the marketplace UI in VS Code, <a href="https://github.com/microsoft/vscode/issues/new?assignees=&labels=&template=bug_report.md" data-loc-id="bug.report.link.title">please report the issue</a>.</p>
<h1 data-loc-id="reinstalling.extension.heading">Reinstalling the C/C++ Extension</h1>
<p data-loc-id="reinstall.extension.text1">When reinstalling an equivalent version of an extension, VS Code may reuse the existing extension directory. To prevent this from occurring when reinstalling the C/C++ extension, it may be necessary to first delete the existing extension directory.</p>
<p data-loc-id="reinstall.extension.text2">Installed extension directories can be found under one of the following paths under your user directory (`%USERPROFILE%` on Windows, or `$HOME` on Linux and macOS)</p>
<pre><code class="lang-bash">%USERPROFILE%\.vscode\extensions</code></pre>
<pre><code class="lang-bash">%USERPROFILE%\.vscode-insiders\extensions</code></pre>
<pre><code class="lang-bash">%USERPROFILE%\.vscode-exploration\extensions</code></pre>
<p data-loc-id="reinstall.extension.text3">In a remote connection:</p>
<pre><code class="lang-bash">$HOME/.vscode-server/extensions</code></pre>
<pre><code class="lang-bash">$HOME/.vscode-server-insiders/extensions</code></pre>
<pre><code class="lang-bash">$HOME/.vscode-server-exploration/extensions</code></pre>
<p data-loc-id="reinstall.extension.text4">Example paths to installed C/C++ extension directories:</p>
<p data-loc-id="reinstall.extension.text5">On Windows:</p>
<pre><code class="lang-bash">%USERPROFILE%\.vscode\extensions\ms-vscode.cpptools-1.9.0</code></pre>
<p data-loc-id="reinstall.extension.text6">On Linux:</p>
<pre><code class="lang-bash">$HOME/.vscode/extensions/ms-vscode.cpptools-1.9.0</code></pre>
<p data-loc-id="reinstall.extension.text7">Then reinstall via the marketplace UI in VS Code.</p>
<p data-loc-id="reinstall.extension.text8">If the correct version of the extension fails to be deployed by VS Code, the correct VSIX for your system can be <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools" data-loc-id="download.vsix.link.title">downloaded from the VS Code marketplace web site</a> and installed using the 'Install from VSIX...' option under the '...' menu in the marketplace UI in VS Code.</p>

Some files were not shown because too many files have changed in this diff Show More