Compare commits

..
Author SHA1 Message Date
Andrew Wang 7230886a12 Try fix 2021-07-19 14:57:20 -07:00
1141 changed files with 72990 additions and 134999 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
+39
View File
@@ -0,0 +1,39 @@
---
name: Bug Report - Debugger
about: Create a bug report for debugging such as call stack, breakpoints, watch window,
launching or attaching to a debuggee.
title: ''
labels: ''
assignees: ''
---
Bug type: Debugger
<!-- Prior to creating a bug report, 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.
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature Request
about: Suggest an idea for this extension.
title: ''
labels: ''
assignees: ''
---
Type: Feature Request
<!-- Prior to creating a feature request, please review
existing issues at https://github.com/Microsoft/vscode-cpptools/issues
to avoid creating duplicates.
-->
<!-- Describe the feature you'd like. -->
@@ -0,0 +1,45 @@
---
name: Bug Report - General Extension
about: Create a bug report for downloading, installing, or building the extension.
title: ''
labels: ''
assignees: ''
---
Bug type: General
<!-- Prior to creating a bug report, 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,65 @@
---
name: Bug Report - Language Service
about: 'Create a bug report for IntelliSense, autocomplete, code editing, code navigation, etc.'
title: ''
labels: ''
assignees: ''
---
Bug type: Language Service
<!-- Prior to creating a bug report, 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):
- If using SSH remote, specify OS of 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 bug: -->
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. -->
**Code sample and logs**
<!-- Please provide code sample, your c_cpp_properties.json and logs. -->
- Code sample
- 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)
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
<!--
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.
-->
-4
View File
@@ -1,4 +0,0 @@
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
always-auth=true
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
ignore-scripts=true
-86
View File
@@ -1,86 +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.AddComment = void 0;
const ActionBase_1 = require("../common/ActionBase");
const utils_1 = require("../common/utils");
class AddComment extends ActionBase_1.ActionBase {
constructor(github, createdAfter, afterDays, labels, addComment, 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.createdAfter = createdAfter;
this.afterDays = afterDays;
this.addComment = addComment;
this.addLabels = addLabels;
this.removeLabels = removeLabels;
this.setMilestoneId = setMilestoneId;
}
async run() {
const updatedTimestamp = this.afterDays ? (0, utils_1.daysAgoToHumanReadbleDate)(this.afterDays) : undefined;
const query = this.buildQuery((updatedTimestamp ? `updated:<${updatedTimestamp} ` : "") +
(this.createdAfter ? `created:>${this.createdAfter} ` : "") +
"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();
if (hydrated.open && this.validateIssue(hydrated)
// TODO: Verify updated timestamp
) {
// Don't add a comment if already commented on by an action.
let foundActionComment = false;
for await (const commentBatch of issue.getComments()) {
for (const comment of commentBatch) {
if (comment.author.isGitHubApp) {
foundActionComment = true;
break;
}
}
if (foundActionComment)
break;
}
if (foundActionComment) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} already commented on by an action. Ignoring.`);
continue;
}
if (this.addComment) {
(0, utils_1.safeLog)(`Posting comment on issue ${hydrated.number}`);
await issue.postComment(this.addComment);
}
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.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)(`Processing issue ${hydrated.number}.`);
}
else {
if (!hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is not open. Ignoring`);
}
}
}
}
}
}
exports.AddComment = AddComment;
//# sourceMappingURL=AddComment.js.map
-98
View File
@@ -1,98 +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 AddComment extends ActionBase {
constructor(
private github: GitHub,
private createdAfter: string | undefined,
private afterDays: number,
labels: string,
private addComment: 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 = this.afterDays ? daysAgoToHumanReadbleDate(this.afterDays) : undefined;
const query = this.buildQuery(
(updatedTimestamp ? `updated:<${updatedTimestamp} ` : "") +
(this.createdAfter ? `created:>${this.createdAfter} ` : "") +
"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();
if (hydrated.open && this.validateIssue(hydrated)
// TODO: Verify updated timestamp
) {
// Don't add a comment if already commented on by an action.
let foundActionComment = false;
for await (const commentBatch of issue.getComments()) {
for (const comment of commentBatch) {
if (comment.author.isGitHubApp) {
foundActionComment = true;
break;
}
}
if (foundActionComment)
break;
}
if (foundActionComment) {
safeLog(`Issue ${hydrated.number} already commented on by an action. Ignoring.`);
continue;
}
if (this.addComment) {
safeLog(`Posting comment on issue ${hydrated.number}`);
await issue.postComment(this.addComment);
}
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.setMilestoneId != undefined) {
safeLog(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
safeLog(`Processing issue ${hydrated.number}.`);
} else {
if (!hydrated.open) {
safeLog(`Issue ${hydrated.number} is not open. Ignoring`);
}
}
}
}
}
}
-42
View File
@@ -1,42 +0,0 @@
name: Add Comment and Label
description: Add comment (etc) to issues that are marked with a specified label (etc)
inputs:
token:
description: GitHub token with issue, comment, and label read/write permissions
default: ${{ github.token }}
createdAfter:
description: Creation date after which to be considered.
required: false
afterDays:
description: Days to wait before performing this action (may be 0).
required: false
addComment:
description: Comment to add
labels:
description: items with these labels will be considered. May be "*".
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)
ignoreLabels:
description: items with these labels will not be considered
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)
addLabels:
description: Labels to add to issue.
removeLabels:
description: Labels to remove from issue.
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: 'node24'
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 AddComment_1 = require("./AddComment");
const Action_1 = require("../common/Action");
class AddCommentAction extends Action_1.Action {
constructor() {
super(...arguments);
this.id = 'AddComment';
}
async onTriggered(github) {
await new AddComment_1.AddComment(github, (0, utils_1.getInput)('createdAfter') || undefined, +((0, utils_1.getInput)('afterDays') || 0), (0, utils_1.getRequiredInput)('labels'), (0, utils_1.getInput)('addComment') || '', (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 AddCommentAction().run(); // eslint-disable-line
//# sourceMappingURL=index.js.map
-36
View File
@@ -1,36 +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 { AddComment } from './AddComment'
import { Action } from '../common/Action'
class AddCommentAction extends Action {
id = 'AddComment';
async onTriggered(github: OctoKit) {
await new AddComment(
github,
getInput('createdAfter') || undefined,
+(getInput('afterDays') || 0),
getRequiredInput('labels'),
getInput('addComment') || '',
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 AddCommentAction().run(); // eslint-disable-line
+5 -5
View File
@@ -15,8 +15,8 @@ class Locker extends ActionBase_1.ActionBase {
this.daysSinceUpdate = daysSinceUpdate;
}
async run() {
const closedTimestamp = (0, utils_1.daysAgoToHumanReadbleDate)(this.daysSinceClose);
const updatedTimestamp = (0, utils_1.daysAgoToHumanReadbleDate)(this.daysSinceUpdate);
const closedTimestamp = utils_1.daysAgoToHumanReadbleDate(this.daysSinceClose);
const updatedTimestamp = 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) => {
@@ -24,15 +24,15 @@ class Locker extends ActionBase_1.ActionBase {
if (!hydrated.locked && hydrated.open === false && this.validateIssue(hydrated)
// TODO: Verify closed and updated timestamps
) {
(0, utils_1.safeLog)(`Locking issue ${hydrated.number}`);
console.log(`Locking issue ${hydrated.number}`);
await issue.lockIssue();
}
else {
if (hydrated.locked) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is already locked. Ignoring`);
console.log(`Issue ${hydrated.number} is already locked. Ignoring`);
}
else if (hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is open. Ignoring`);
console.log(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}));
+10 -10
View File
@@ -3,9 +3,9 @@
* 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';
import { GitHub, Issue } from '../api/api'
import { daysAgoToHumanReadbleDate } from '../common/utils'
import { ActionBase } from '../common/ActionBase'
export class Locker extends ActionBase {
constructor(
@@ -26,26 +26,26 @@ export class Locker extends ActionBase {
}
async run() {
const closedTimestamp = daysAgoToHumanReadbleDate(this.daysSinceClose);
const updatedTimestamp = daysAgoToHumanReadbleDate(this.daysSinceUpdate);
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();
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();
console.log(`Locking issue ${hydrated.number}`)
await issue.lockIssue()
} else {
if (hydrated.locked) {
safeLog(`Issue ${hydrated.number} is already locked. Ignoring`);
console.log(`Issue ${hydrated.number} is already locked. Ignoring`)
} else if (hydrated.open) {
safeLog(`Issue ${hydrated.number} is open. Ignoring`);
console.log(`Issue ${hydrated.number} is open. Ignoring`)
}
}
}),
+2 -2
View File
@@ -15,7 +15,7 @@ inputs:
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will be considered. May be "*".
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:
@@ -29,5 +29,5 @@ inputs:
readonly:
description: If true, changes are not applied.
runs:
using: 'node24'
using: 'node12'
main: 'index.js'
+1 -1
View File
@@ -13,7 +13,7 @@ class LockerAction extends Action_1.Action {
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();
await new Locker_1.Locker(github, +utils_1.getRequiredInput('daysSinceClose'), +utils_1.getRequiredInput('daysSinceUpdate'), utils_1.getInput('labels') || undefined, utils_1.getInput('milestoneName') || undefined, utils_1.getInput('milestoneId') || undefined, utils_1.getInput('ignoreLabels') || undefined, utils_1.getInput('ignoreMilestoneNames') || undefined, utils_1.getInput('ignoreMilestoneIds') || undefined, +(utils_1.getInput('minimumVotes') || 0), +(utils_1.getInput('maximumVotes') || 9999999)).run();
}
}
new LockerAction().run(); // eslint-disable-line
+7 -7
View File
@@ -3,13 +3,13 @@
* 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';
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';
id = 'Locker'
async onTriggered(github: OctoKit) {
await new Locker(
@@ -24,8 +24,8 @@ class LockerAction extends Action {
getInput('ignoreMilestoneIds') || undefined,
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999)
).run();
).run()
}
}
new LockerAction().run(); // eslint-disable-line
new LockerAction().run() // eslint-disable-line
+8 -9
View File
@@ -5,7 +5,6 @@
*--------------------------------------------------------------------------------------------*/
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) {
@@ -20,7 +19,7 @@ class Reopener extends ActionBase_1.ActionBase {
async run() {
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
(0, utils_1.safeLog)(`alsoApplyToOpenIssues: ${this.alsoApplyToOpenIssues}`);
console.log(`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) => {
@@ -29,17 +28,17 @@ class Reopener extends ActionBase_1.ActionBase {
// TODO: Verify closed and updated timestamps
) {
if (hydrated.open === false) {
(0, utils_1.safeLog)(`Reopening issue ${hydrated.number}`);
console.log(`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}`);
console.log(`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}`);
console.log(`Removing label on issue ${hydrated.number}: ${removeLabel}`);
await issue.removeLabel(removeLabel);
}
}
@@ -47,22 +46,22 @@ class Reopener extends ActionBase_1.ActionBase {
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}`);
console.log(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
if (this.reopenComment) {
(0, utils_1.safeLog)(`Posting comment to issue ${hydrated.number}.`);
console.log(`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`);
console.log(`Issue ${hydrated.number} is locked. Ignoring`);
}
else if (!this.alsoApplyToOpenIssues && hydrated.open) {
(0, utils_1.safeLog)(`Issue ${hydrated.number} is open. Ignoring`);
console.log(`Issue ${hydrated.number} is open. Ignoring`);
}
}
}));
+16 -17
View File
@@ -3,9 +3,8 @@
* 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';
import { GitHub, Issue } from '../api/api'
import { ActionBase } from '../common/ActionBase'
export class Reopener extends ActionBase {
constructor(
@@ -32,50 +31,50 @@ export class Reopener extends ActionBase {
const addLabelsSet = this.addLabels ? this.addLabels.split(',') : [];
const removeLabelsSet = this.removeLabels ? this.removeLabels.split(',') : [];
safeLog(`alsoApplyToOpenIssues: ${this.alsoApplyToOpenIssues}`);
console.log(`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();
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();
console.log(`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);
console.log(`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);
console.log(`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);
console.log(`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);
console.log(`Posting comment to issue ${hydrated.number}.`)
await issue.postComment(this.reopenComment)
}
} else {
if (hydrated.locked) {
safeLog(`Issue ${hydrated.number} is locked. Ignoring`);
console.log(`Issue ${hydrated.number} is locked. Ignoring`)
} else if (!this.alsoApplyToOpenIssues && hydrated.open) {
safeLog(`Issue ${hydrated.number} is open. Ignoring`);
console.log(`Issue ${hydrated.number} is open. Ignoring`)
}
}
}),
+2 -2
View File
@@ -19,7 +19,7 @@ inputs:
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will be considered. May be "*".
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:
@@ -33,5 +33,5 @@ inputs:
readonly:
description: If true, changes are not applied.
runs:
using: 'node24'
using: 'node12'
main: 'index.js'
+3 -3
View File
@@ -10,11 +10,11 @@ const Action_1 = require("../common/Action");
class ReopenerAction extends Action_1.Action {
constructor() {
super(...arguments);
this.id = 'Reopener';
this.id = 'Locker';
}
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();
const alsoApplyToOpenIssues = utils_1.getInput('alsoApplyToOpenIssues');
await new Reopener_1.Reopener(github, alsoApplyToOpenIssues != undefined && alsoApplyToOpenIssues.toLowerCase() == 'true', utils_1.getInput('addLabels') || undefined, utils_1.getInput('removeLabels') || undefined, utils_1.getInput('reopenComment') || '', utils_1.getInput('setMilestoneId') || undefined, utils_1.getInput('labels') || undefined, utils_1.getInput('milestoneName') || undefined, utils_1.getInput('milestoneId') || undefined, utils_1.getInput('ignoreLabels') || undefined, utils_1.getInput('ignoreMilestoneNames') || undefined, utils_1.getInput('ignoreMilestoneIds') || undefined, +(utils_1.getInput('minimumVotes') || 0), +(utils_1.getInput('maximumVotes') || 9999999)).run();
}
}
new ReopenerAction().run(); // eslint-disable-line
+7 -7
View File
@@ -3,13 +3,13 @@
* 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';
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';
id = 'Locker'
async onTriggered(github: OctoKit) {
const alsoApplyToOpenIssues: string | undefined = getInput('alsoApplyToOpenIssues');
@@ -28,8 +28,8 @@ class ReopenerAction extends Action {
getInput('ignoreMilestoneIds') || undefined,
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999)
).run();
).run()
}
}
new ReopenerAction().run(); // eslint-disable-line
new ReopenerAction().run() // eslint-disable-line
+105 -105
View File
@@ -1,106 +1,106 @@
"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 = this.closeDays ? (0, utils_1.daysAgoToHumanReadbleDate)(this.closeDays) : undefined;
const pingTimestamp = this.pingDays ? (0, utils_1.daysAgoToTimestamp)(this.pingDays) : undefined;
const query = this.buildQuery((updatedTimestamp ? `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;
"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 = utils_1.daysAgoToHumanReadbleDate(this.closeDays);
const pingTimestamp = this.pingDays ? 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) {
console.log(`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Closing.`);
}
else {
console.log(`No comments on issue ${hydrated.number}. Closing.`);
}
}
if (this.closeComment) {
console.log(`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) {
console.log(`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) {
console.log(`Adding label on issue ${hydrated.number}: ${addLabel}`);
await issue.addLabel(addLabel);
}
}
}
await issue.closeIssue();
if (this.setMilestoneId != undefined) {
console.log(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
}
console.log(`Closing issue ${hydrated.number}.`);
}
else {
// Ping
if (hydrated.updatedAt < pingTimestamp && hydrated.assignee) {
console.log(`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 {
console.log(`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Skipping.${hydrated.assignee ? ' cc @' + hydrated.assignee : ''}`);
}
}
}
else {
if (!hydrated.open) {
console.log(`Issue ${hydrated.number} is not open. Ignoring`);
}
}
}
}
}
}
exports.StaleCloser = StaleCloser;
//# sourceMappingURL=StaleCloser.js.map
+29 -29
View File
@@ -3,9 +3,9 @@
* 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';
import { GitHub } from '../api/api'
import { ActionBase } from '../common/ActionBase'
import { daysAgoToHumanReadbleDate, daysAgoToTimestamp } from '../common/utils'
export class StaleCloser extends ActionBase {
constructor(
@@ -33,22 +33,22 @@ export class StaleCloser extends ActionBase {
}
async run() {
const updatedTimestamp = this.closeDays ? daysAgoToHumanReadbleDate(this.closeDays) : undefined;
const updatedTimestamp = daysAgoToHumanReadbleDate(this.closeDays)
const pingTimestamp = this.pingDays ? daysAgoToTimestamp(this.pingDays) : undefined;
const query = this.buildQuery((updatedTimestamp ? `updated:<${updatedTimestamp} ` : "") + "is:open is:unlocked");
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();
const hydrated = await issue.getIssue()
const lastCommentIterator = await issue.getComments(true).next()
if (lastCommentIterator.done) {
throw Error('Unexpected comment data');
throw Error('Unexpected comment data')
}
const lastComment = lastCommentIterator.value[0];
const lastComment = lastCommentIterator.value[0]
if (hydrated.open && this.validateIssue(hydrated)
// TODO: Verify updated timestamp
@@ -63,63 +63,63 @@ export class StaleCloser extends ActionBase {
) {
if (pingTimestamp != undefined) {
if (lastComment) {
safeLog(
console.log(
`Last comment on issue ${hydrated.number} by ${lastComment.author.name}. Closing.`,
);
)
} else {
safeLog(`No comments on issue ${hydrated.number}. Closing.`);
console.log(`No comments on issue ${hydrated.number}. Closing.`)
}
}
if (this.closeComment) {
safeLog(`Posting comment on issue ${hydrated.number}`);
await issue.postComment(this.closeComment);
console.log(`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);
console.log(`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);
console.log(`Adding label on issue ${hydrated.number}: ${addLabel}`)
await issue.addLabel(addLabel)
}
}
}
await issue.closeIssue("not_planned");
await issue.closeIssue()
if (this.setMilestoneId != undefined) {
safeLog(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`);
await issue.setMilestone(+this.setMilestoneId);
console.log(`Setting milestone of issue ${hydrated.number} to id ${+this.setMilestoneId}`)
await issue.setMilestone(+this.setMilestoneId)
}
safeLog(`Closing issue ${hydrated.number}.`);
console.log(`Closing issue ${hydrated.number}.`)
} else {
// Ping
// Ping
if (hydrated.updatedAt < pingTimestamp && hydrated.assignee) {
safeLog(
console.log(
`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(
console.log(
`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`);
console.log(`Issue ${hydrated.number} is not open. Ignoring`)
}
}
}
+2 -2
View File
@@ -20,7 +20,7 @@ inputs:
milestoneId:
description: items with these milestones will be considered (id only, must match name)
labels:
description: items with these labels will be considered. May be "*".
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 "*".
@@ -43,5 +43,5 @@ inputs:
readonly:
description: If true, changes are not applied.
runs:
using: 'node24'
using: 'node12'
main: 'index.js'
+20 -20
View File
@@ -1,21 +1,21 @@
"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
"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, +utils_1.getRequiredInput('closeDays'), utils_1.getRequiredInput('labels'), utils_1.getInput('closeComment') || '', +(utils_1.getInput('pingDays') || 0), utils_1.getInput('pingComment') || '', ((_a = utils_1.getInput('additionalTeam')) !== null && _a !== void 0 ? _a : '').split(','), utils_1.getInput('addLabels') || undefined, utils_1.getInput('removeLabels') || undefined, utils_1.getInput('setMilestoneId') || undefined, utils_1.getInput('milestoneName') || undefined, utils_1.getInput('milestoneId') || undefined, utils_1.getInput('ignoreLabels') || undefined, utils_1.getInput('ignoreMilestoneNames') || undefined, utils_1.getInput('ignoreMilestoneIds') || undefined, +(utils_1.getInput('minimumVotes') || 0), +(utils_1.getInput('maximumVotes') || 9999999), utils_1.getInput('involves') || undefined).run();
}
}
new StaleCloserAction().run(); // eslint-disable-line
//# sourceMappingURL=index.js.map
+3 -3
View File
@@ -9,7 +9,7 @@ import { StaleCloser } from './StaleCloser'
import { Action } from '../common/Action'
class StaleCloserAction extends Action {
id = 'StaleCloser';
id = 'StaleCloser'
async onTriggered(github: OctoKit) {
await new StaleCloser(
@@ -31,8 +31,8 @@ class StaleCloserAction extends Action {
+(getInput('minimumVotes') || 0),
+(getInput('maximumVotes') || 9999999),
getInput('involves') || undefined
).run();
).run()
}
}
new StaleCloserAction().run(); // eslint-disable-line
new StaleCloserAction().run() // eslint-disable-line
+56 -79
View File
@@ -4,53 +4,43 @@
*--------------------------------------------------------------------------------------------*/
export interface GitHub {
repoOwner: string;
repoName: string;
query(query: Query): AsyncIterableIterator<GitHubIssue[]>
query(query: Query): AsyncIterableIterator<GitHubIssue[]>;
hasWriteAccess(user: User): Promise<boolean>
hasWriteAccess(user: User): Promise<boolean>;
repoHasLabel(label: string): Promise<boolean>
createLabel(label: string, color: string, description: string): Promise<void>
deleteLabel(label: string): Promise<void>
repoHasLabel(label: string): Promise<boolean>;
createLabel(label: string, color: string, description: string): Promise<void>;
deleteLabel(label: string): Promise<void>;
readConfig(path: string): Promise<any>
readConfig(path: string): Promise<any>;
dispatch(title: string): Promise<void>
dispatch(title: string): Promise<void>;
createIssue(owner: string, repo: string, title: string, body: 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>;
releaseContainsCommit(release: string, commit: string): Promise<'yes' | 'no' | 'unknown'>
}
export interface GitHubIssue extends GitHub {
getIssue(): Promise<Issue>;
getIssue(): Promise<Issue>
postComment(body: string): Promise<void>;
deleteComment(id: number): Promise<void>;
getComments(last?: boolean): AsyncIterableIterator<Comment[]>;
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>;
closeIssue(): Promise<void>
lockIssue(): Promise<void>
reopenIssue(): Promise<void>
setMilestone(milestoneId: number): Promise<void>;
setMilestone(milestoneId: number): Promise<void>
addLabel(label: string): Promise<void>;
removeLabel(label: string): Promise<void>;
addLabel(label: string): Promise<void>
removeLabel(label: string): Promise<void>
addAssignee(assignee: string): Promise<void>;
removeAssignee(assignee: string): Promise<void>;
addAssignee(assignee: string): Promise<void>
removeAssignee(assignee: string): Promise<void>
getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined>;
getClosingInfo(): Promise<{ hash: string | undefined; timestamp: number } | undefined>
}
type SortVar =
@@ -64,60 +54,47 @@ type SortVar =
| 'reactions-tada'
| 'interactions'
| 'created'
| 'updated';
type SortOrder = 'asc' | 'desc';
| 'updated'
type SortOrder = 'asc' | 'desc'
export type Reactions = {
'+1': number;
'-1': number;
laugh: number;
hooray: number;
confused: number;
heart: number;
rocket: number;
eyes: number;
};
'+1': number
'-1': number
laugh: number
hooray: number
confused: number
heart: number
rocket: number
eyes: number
}
export interface User {
name: string;
isGitHubApp?: boolean;
name: string
isGitHubApp?: boolean
}
export interface Comment {
author: User;
body: string;
id: number;
timestamp: number;
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';
author: User
body: string
title: string
labels: string[]
open: boolean
locked: boolean
number: number
numComments: number
reactions: Reactions
milestoneId: number | null
assignee?: string
createdAt: number
updatedAt: number
closedAt?: number
}
export interface Query {
q: string;
sort?: SortVar;
order?: SortOrder;
q: string
sort?: SortVar
order?: SortOrder
}
+93 -172
View File
@@ -5,17 +5,12 @@
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.OctoKitIssue = exports.OctoKit = exports.getNumRequests = void 0;
const core_1 = require("@actions/core");
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;
exports.getNumRequests = () => numRequests;
class OctoKit {
get octokit() {
numRequests++;
return this._octokit;
}
constructor(token, params, options = { readonly: false }) {
this.token = token;
this.params = params;
@@ -23,93 +18,73 @@ class OctoKit {
// 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;
this._octokit = new github_1.GitHub(token);
}
getIssueByNumber(number) {
return new OctoKitIssue(this.token, this.params, { number: number });
get octokit() {
numRequests++;
return this._octokit;
}
// 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 = {
console.log(`Querying for ${q}:`);
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
...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));
await new Promise((resolve) => setTimeout(resolve, 3000));
}
else {
await new Promise((resolve) => setTimeout(resolve, 30000));
}
};
for await (const pageResponse of this.octokit.paginate.iterator(this.octokit.rest.search.issuesAndPullRequests, options)) {
for await (const pageResponse of this.octokit.paginate.iterator(options)) {
await timeout();
numRequests++;
const page = pageResponse.data;
(0, utils_1.safeLog)(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`);
console.log(`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}`);
core_1.debug(`Creating issue \`${title}\` on ${owner}/${repo}`);
if (!this.options.readonly)
await this.octokit.rest.issues.create({ owner, repo, title, body });
await this.octokit.issues.create({ owner, repo, title, body });
}
octokitIssueToIssue(issue) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
var _a, _b, _c, _d, _e, _f;
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 : '',
author: { name: issue.user.login, isGitHubApp: issue.user.type === 'Bot' },
body: issue.body,
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 : ''); }),
labels: issue.labels.map((label) => label.name),
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,
assignee: (_b = (_a = issue.assignee) === null || _a === void 0 ? void 0 : _a.login) !== null && _b !== void 0 ? _b : (_d = (_c = issue.assignees) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.login,
milestoneId: (_f = (_e = issue.milestone) === null || _e === void 0 ? void 0 : _e.number) !== null && _f !== void 0 ? _f : 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);
core_1.debug('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({
core_1.debug('Fetching permissions for ' + user);
const permissions = (await this.octokit.repos.getCollaboratorPermissionLevel({
...this.params,
username: user.name,
})).data.permission;
@@ -117,44 +92,42 @@ class OctoKit {
}
async repoHasLabel(name) {
try {
await this.octokit.rest.issues.getLabel({ ...this.params, name });
await this.octokit.issues.getLabel({ ...this.params, name });
return true;
}
catch (err) {
const statusErorr = err;
if (statusErorr.status === 404) {
if (err.status === 404) {
return this.options.readonly && this.mockLabels.has(name);
}
throw err;
}
}
async createLabel(name, color, description) {
(0, utils_1.safeLog)('Creating label ' + name);
core_1.debug('Creating label ' + name);
if (!this.options.readonly)
await this.octokit.rest.issues.createLabel({ ...this.params, color, description, name });
await this.octokit.issues.createLabel({ ...this.params, color, description, name });
else
this.mockLabels.add(name);
}
async deleteLabel(name) {
(0, utils_1.safeLog)('Deleting label ' + name);
core_1.debug('Deleting label ' + name);
try {
if (!this.options.readonly)
await this.octokit.rest.issues.deleteLabel({ ...this.params, name });
await this.octokit.issues.deleteLabel({ ...this.params, name });
}
catch (err) {
const statusErorr = err;
if (statusErorr.status === 404) {
if (err.status === 404) {
return;
}
throw err;
}
}
async readConfig(path) {
(0, utils_1.safeLog)('Reading config at ' + path);
core_1.debug('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) {
const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data;
if ('type' in data && data.type === 'file') {
if (data.encoding === 'base64' && data.content) {
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'));
}
@@ -167,10 +140,7 @@ class OctoKit {
}
}
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) => {
return new Promise((resolve, reject) => child_process_1.exec(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => {
if (!err || err.code === 1) {
resolve(!err ? 'yes' : 'no');
}
@@ -187,31 +157,10 @@ class OctoKit {
}
}));
}
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);
core_1.debug('Dispatching ' + title);
if (!this.options.readonly)
await this.octokit.rest.repos.createDispatchEvent({ ...this.params, event_type: title });
await this.octokit.repos.createDispatchEvent({ ...this.params, event_type: title });
}
}
exports.OctoKit = OctoKit;
@@ -220,12 +169,12 @@ class OctoKitIssue extends OctoKit {
super(token, params, options);
this.params = params;
this.issueData = issueData;
(0, utils_1.safeLog)('running bot on issue', issueData.number);
console.log('running bot on issue', issueData.number);
}
async addAssignee(assignee) {
(0, utils_1.safeLog)('Adding assignee ' + assignee + ' to ' + this.issueData.number);
core_1.debug('Adding assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.addAssignees({
await this.octokit.issues.addAssignees({
...this.params,
issue_number: this.issueData.number,
assignees: [assignee],
@@ -233,64 +182,45 @@ class OctoKitIssue extends OctoKit {
}
}
async removeAssignee(assignee) {
(0, utils_1.safeLog)('Removing assignee ' + assignee + ' to ' + this.issueData.number);
core_1.debug('Removing assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) {
await this.octokit.rest.issues.removeAssignees({
await this.octokit.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({
async closeIssue() {
core_1.debug('Closing issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.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);
core_1.debug('Reopening issue ' + this.issueData.number);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
await this.octokit.issues.update({
...this.params,
issue_number: this.issueData.number,
state: 'open',
});
}
async lockIssue() {
(0, utils_1.safeLog)('Locking issue ' + this.issueData.number);
core_1.debug('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 });
await this.octokit.issues.lock({ ...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);
core_1.debug('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({
console.log('Fetching issue ' + this.issueData.number);
const issue = (await this.octokit.issues.get({
...this.params,
issue_number: this.issueData.number,
mediaType: { previews: ['squirrel-girl'] },
@@ -298,83 +228,77 @@ class OctoKitIssue extends OctoKit {
return (this.issueData = this.octokitIssueToIssue(issue));
}
async postComment(body) {
(0, utils_1.safeLog)(`Posting comment on ${this.issueData.number}`);
core_1.debug(`Posting comment ${body} on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.createComment({
await this.octokit.issues.createComment({
...this.params,
issue_number: this.issueData.number,
body,
});
}
async deleteComment(id) {
(0, utils_1.safeLog)(`Deleting comment ${id} on ${this.issueData.number}`);
core_1.debug(`Deleting comment ${id} on ${this.issueData.number}`);
if (!this.options.readonly)
await this.octokit.rest.issues.deleteComment({
await this.octokit.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}`);
core_1.debug(`Setting milestone for ${this.issueData.number} to ${milestoneId}`);
if (!this.options.readonly)
await this.octokit.rest.issues.update({
await this.octokit.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, {
core_1.debug('Fetching comments for ' + this.issueData.number);
const response = this.octokit.paginate.iterator(this.octokit.issues.listComments.endpoint.merge({
...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),
});
});
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) {
(0, utils_1.safeLog)(`Adding label ${name} to ${this.issueData.number}`);
core_1.debug(`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({
await this.octokit.issues.addLabels({
...this.params,
issue_number: this.issueData.number,
labels: [name],
});
}
async getAssigner(assignee) {
var _a, _b;
const options = {
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
...this.params,
issue_number: this.issueData.number,
};
});
let assigner;
for await (const event of this.octokit.paginate.iterator(this.octokit.rest.issues.listEventsForTimeline, options)) {
for await (const event of this.octokit.paginate.iterator(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 (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.');
@@ -382,26 +306,25 @@ class OctoKitIssue extends OctoKit {
return assigner;
}
async removeLabel(name) {
(0, utils_1.safeLog)(`Removing label ${name} from ${this.issueData.number}`);
core_1.debug(`Removing label ${name} from ${this.issueData.number}`);
try {
if (!this.options.readonly)
await this.octokit.rest.issues.removeLabel({
await this.octokit.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`);
if (err.status === 404) {
console.log(`Label ${name} not found on issue`);
return;
}
throw err;
}
}
async getClosingInfo(alreadyChecked = []) {
var _a, _b, _c, _d, _e, _f, _g, _h;
var _a, _b, _c, _d, _e, _f, _g;
if (alreadyChecked.includes(this.issueData.number)) {
return undefined;
}
@@ -409,21 +332,22 @@ class OctoKitIssue extends OctoKit {
if ((await this.getIssue()).open) {
return;
}
const closingHashComment = /(?:\\|\/)closedWith (?:https:\/\/github\.com\/microsoft\/vscode\/commit\/)?([a-fA-F0-9]{7,40})/;
const options = {
const closingHashComment = /(?:\\|\/)closedWith (\S*)/;
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
...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)) {
for await (const event of this.octokit.paginate.iterator(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()))) {
timelineEvent.commit_url
.toLowerCase()
.includes(`/${this.params.owner}/${this.params.repo}/`.toLowerCase())) {
closingCommit = {
hash: timelineEvent.commit_id,
timestamp: +new Date(timelineEvent.created_at),
@@ -432,18 +356,15 @@ class OctoKitIssue extends OctoKit {
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')) &&
if (timelineEvent.event === 'commented' &&
!((_a = timelineEvent.body) === null || _a === void 0 ? void 0 : _a.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()))) {
if (timelineEvent.event === 'cross-referenced' && ((_c = (_b = timelineEvent.source) === null || _b === void 0 ? void 0 : _b.issue) === null || _c === void 0 ? void 0 : _c.number) && ((_f = (_e = (_d = timelineEvent.source) === null || _d === void 0 ? void 0 : _d.issue) === null || _e === void 0 ? void 0 : _e.pull_request) === null || _f === void 0 ? void 0 : _f.url.includes(`/${this.params.owner}/${this.params.repo}/`.toLowerCase()))) {
crossReferencing.push(timelineEvent.source.issue.number);
}
}
@@ -454,16 +375,16 @@ class OctoKitIssue extends OctoKit {
for (const id of crossReferencing.reverse()) {
const closed = await new OctoKitIssue(this.token, this.params, {
number: id,
}).getClosingInfo(alreadyChecked);
}, this.options).getClosingInfo(alreadyChecked);
if (closed) {
if (Math.abs(closed.timestamp - ((_h = (await this.getIssue()).closedAt) !== null && _h !== void 0 ? _h : 0)) < 5000) {
if (Math.abs(closed.timestamp - ((_g = (await this.getIssue()).closedAt) !== null && _g !== void 0 ? _g : 0)) < 5000) {
closingCommit = closed;
break;
}
}
}
}
(0, utils_1.safeLog)(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`);
console.log(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`);
return closingCommit;
}
}
+170 -259
View File
@@ -3,242 +3,181 @@
* 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';
import { debug } from '@actions/core'
import { GitHub as GitHubAPI } from '@actions/github'
import { Octokit } from '@octokit/rest'
import { exec } from 'child_process'
import { Comment, GitHub, GitHubIssue, Issue, Query, User } from './api'
let numRequests = 0;
export const getNumRequests = () => numRequests;
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;
private _octokit: GitHubAPI
protected get octokit(): GitHubAPI {
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;
protected mockLabels: Set<string> = new Set()
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 });
this._octokit = new GitHubAPI(token)
}
// 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 q = query.q + ` repo:${this.params.owner}/${this.params.repo}`
console.log(`Querying for ${q}:`)
const options = {
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
...query,
q,
per_page: 100,
headers: { Accept: 'application/vnd.github.squirrel-girl-preview+json' },
};
})
let pageNum = 0;
let pageNum = 0
const timeout = async () => {
if (pageNum < 2) {
/* pass */
} else if (pageNum < 4) {
await new Promise((resolve) => setTimeout(resolve, 10000));
await new Promise((resolve) => setTimeout(resolve, 3000))
} else {
await new Promise((resolve) => setTimeout(resolve, 30000));
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(' ')}`);
for await (const pageResponse of this.octokit.paginate.iterator(options)) {
await timeout()
numRequests++
const page: Array<Octokit.SearchIssuesAndPullRequestsResponseItemsItem> = pageResponse.data
console.log(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`)
yield page.map(
(issue) =>
new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue), this.options),
);
(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 });
debug(`Creating issue \`${title}\` on ${owner}/${repo}`)
if (!this.options.readonly) await this.octokit.issues.create({ owner, repo, title, body })
}
protected octokitIssueToIssue(issue: IssueGetResponse): Issue {
protected octokitIssueToIssue(
issue: Octokit.IssuesGetResponse | Octokit.SearchIssuesAndPullRequestsResponseItemsItem,
): Issue {
return {
author: { name: issue.user?.login ?? 'unkown', isGitHubApp: issue.user?.type === 'Bot' },
body: issue.body ?? '',
author: { name: issue.user.login, 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 ?? '')),
labels: (issue.labels as Octokit.IssuesGetLabelResponse[]).map((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,
assignee: issue.assignee?.login ?? (issue as any).assignees?.[0]?.login,
milestoneId: issue.milestone?.number ?? 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;
closedAt: issue.closed_at ? +new Date((issue.closed_at as unknown) as string) : undefined,
}
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> = {};
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];
debug('Got permissions from cache for ' + user)
return this.writeAccessCache[user.name]
}
safeLog('Fetching permissions for ' + user.name);
debug('Fetching permissions for ' + user)
const permissions = (
await this.octokit.rest.repos.getCollaboratorPermissionLevel({
await this.octokit.repos.getCollaboratorPermissionLevel({
...this.params,
username: user.name,
})
).data.permission;
return (this.writeAccessCache[user.name] = permissions === 'admin' || permissions === 'write');
).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;
await this.octokit.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);
if (err.status === 404) {
return this.options.readonly && this.mockLabels.has(name)
}
throw err;
throw err
}
}
async createLabel(name: string, color: string, description: string): Promise<void> {
safeLog('Creating label ' + name);
debug('Creating label ' + name)
if (!this.options.readonly)
await this.octokit.rest.issues.createLabel({ ...this.params, color, description, name });
else this.mockLabels.add(name);
await this.octokit.issues.createLabel({ ...this.params, color, description, name })
else this.mockLabels.add(name)
}
async deleteLabel(name: string): Promise<void> {
safeLog('Deleting label ' + name);
debug('Deleting label ' + name)
try {
if (!this.options.readonly) await this.octokit.rest.issues.deleteLabel({ ...this.params, name });
if (!this.options.readonly) await this.octokit.issues.deleteLabel({ ...this.params, name })
} catch (err) {
const statusErorr = err as RequestError;
if (statusErorr.status === 404) {
return;
if (err.status === 404) {
return
}
throw err;
throw err
}
}
async readConfig(path: string): Promise<any> {
safeLog('Reading config at ' + path);
const repoPath = `.github/${path}.json`;
debug('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) {
const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data
if ('type' in data && data.type === 'file') {
if (data.encoding === 'base64' && data.content) {
return JSON.parse(Buffer.from(data.content, 'base64').toString('utf-8'));
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(`Could not read contents "${data.content}" in encoding "${data.encoding}"`)
}
throw Error('Found directory at config path when expecting file' + JSON.stringify(data));
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));
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');
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');
resolve('no')
} else if (err.message.includes(`Not a valid commit name ${commit}`)) {
// commit is probably in a different repo.
resolve('unknown');
resolve('unknown')
} else {
reject(err);
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);
debug('Dispatching ' + title)
if (!this.options.readonly)
await this.octokit.rest.repos.createDispatchEvent({ ...this.params, event_type: title });
await this.octokit.repos.createDispatchEvent({ ...this.params, event_type: title })
}
}
@@ -249,206 +188,184 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
private issueData: { number: number } | Issue,
options: { readonly: boolean } = { readonly: false },
) {
super(token, params, options);
safeLog('running bot on issue', issueData.number);
super(token, params, options)
console.log('running bot on issue', issueData.number)
}
async addAssignee(assignee: string): Promise<void> {
safeLog('Adding assignee ' + assignee + ' to ' + this.issueData.number);
debug('Adding assignee ' + assignee + ' to ' + this.issueData.number)
if (!this.options.readonly) {
await this.octokit.rest.issues.addAssignees({
await this.octokit.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);
debug('Removing assignee ' + assignee + ' to ' + this.issueData.number)
if (!this.options.readonly) {
await this.octokit.rest.issues.removeAssignees({
await this.octokit.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({
async closeIssue(): Promise<void> {
debug('Closing issue ' + this.issueData.number)
if (!this.options.readonly)
await this.octokit.issues.update({
...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);
});
}
state: 'closed',
})
}
async reopenIssue(): Promise<void> {
safeLog('Reopening issue ' + this.issueData.number);
debug('Reopening issue ' + this.issueData.number)
if (!this.options.readonly)
await this.octokit.rest.issues.update({
await this.octokit.issues.update({
...this.params,
issue_number: this.issueData.number,
state: 'open',
});
})
}
async lockIssue(): Promise<void> {
safeLog('Locking issue ' + this.issueData.number);
debug('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 });
await this.octokit.issues.lock({ ...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;
debug('Got issue data from query result ' + this.issueData.number)
return this.issueData
}
safeLog('Fetching issue ' + this.issueData.number);
console.log('Fetching issue ' + this.issueData.number)
const issue = (
await this.octokit.rest.issues.get({
await this.octokit.issues.get({
...this.params,
issue_number: this.issueData.number,
mediaType: { previews: ['squirrel-girl'] },
})
).data;
return (this.issueData = this.octokitIssueToIssue(issue));
).data
return (this.issueData = this.octokitIssueToIssue(issue))
}
async postComment(body: string): Promise<void> {
safeLog(`Posting comment on ${this.issueData.number}`);
debug(`Posting comment ${body} on ${this.issueData.number}`)
if (!this.options.readonly)
await this.octokit.rest.issues.createComment({
await this.octokit.issues.createComment({
...this.params,
issue_number: this.issueData.number,
body,
});
})
}
async deleteComment(id: number): Promise<void> {
safeLog(`Deleting comment ${id} on ${this.issueData.number}`);
debug(`Deleting comment ${id} on ${this.issueData.number}`)
if (!this.options.readonly)
await this.octokit.rest.issues.deleteComment({
await this.octokit.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}`);
debug(`Setting milestone for ${this.issueData.number} to ${milestoneId}`)
if (!this.options.readonly)
await this.octokit.rest.issues.update({
await this.octokit.issues.update({
...this.params,
issue_number: this.issueData.number,
milestone: milestoneId,
});
})
}
async *getComments(last?: boolean): AsyncIterableIterator<Comment[]> {
safeLog('Fetching comments for ' + this.issueData.number);
debug('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 } : {}),
});
const response = this.octokit.paginate.iterator(
this.octokit.issues.listComments.endpoint.merge({
...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 ?? '',
numRequests++
yield (page.data as Octokit.IssuesListCommentsResponseItem[]).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}`);
debug(`Adding label ${name} to ${this.issueData.number}`)
if (!(await this.repoHasLabel(name))) {
throw Error(`Action could not execute becuase label ${name} is not defined.`);
throw Error(`Action could not execute becuase label ${name} is not defined.`)
}
if (!this.options.readonly)
await this.octokit.rest.issues.addLabels({
await this.octokit.issues.addLabels({
...this.params,
issue_number: this.issueData.number,
labels: [name],
});
})
}
async getAssigner(assignee: string): Promise<string> {
const options = {
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
...this.params,
issue_number: this.issueData.number,
};
})
let assigner: string | undefined;
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 await (const event of this.octokit.paginate.iterator(options)) {
numRequests++
const timelineEvents = event.data as Octokit.IssuesListEventsForTimelineResponseItem[]
for (const timelineEvent of timelineEvents) {
if (timelineEvent.event === 'assigned' && timelineEvent.assignee?.login === assignee) {
assigner = timelineEvent.actor?.login;
if (
timelineEvent.event === 'assigned' &&
(timelineEvent as any).assignee.login === assignee
) {
assigner = timelineEvent.actor.login
}
}
if (assigner) {
break;
}
}
if (!assigner) {
throw Error('Expected to find ' + assignee + ' in issue timeline but did not.');
throw Error('Expected to find ' + assignee + ' in issue timeline but did not.')
}
return assigner;
return assigner
}
async removeLabel(name: string): Promise<void> {
safeLog(`Removing label ${name} from ${this.issueData.number}`);
debug(`Removing label ${name} from ${this.issueData.number}`)
try {
if (!this.options.readonly)
await this.octokit.rest.issues.removeLabel({
await this.octokit.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;
if (err.status === 404) {
console.log(`Label ${name} not found on issue`)
return
}
throw err;
throw err
}
}
@@ -456,49 +373,43 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
alreadyChecked: number[] = [],
): Promise<{ hash: string | undefined; timestamp: number } | undefined> {
if (alreadyChecked.includes(this.issueData.number)) {
return undefined;
return undefined
}
alreadyChecked.push(this.issueData.number);
alreadyChecked.push(this.issueData.number)
if ((await this.getIssue()).open) {
return;
return
}
const closingHashComment =
/(?:\\|\/)closedWith (?:https:\/\/github\.com\/microsoft\/vscode\/commit\/)?([a-fA-F0-9]{7,40})/;
const closingHashComment = /(?:\\|\/)closedWith (\S*)/
const options = {
const options = this.octokit.issues.listEventsForTimeline.endpoint.merge({
...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++;
})
let closingCommit: { hash: string | undefined; timestamp: number } | undefined
const crossReferencing: number[] = []
for await (const event of this.octokit.paginate.iterator(options)) {
numRequests++
const timelineEvents = event.data;
const timelineEvents = event.data as Octokit.IssuesListEventsForTimelineResponseItem[]
for (const timelineEvent of timelineEvents) {
if (
(timelineEvent.event === 'closed' || timelineEvent.event === 'merged') &&
timelineEvent.created_at &&
timelineEvent.commit_id &&
timelineEvent.commit_url
?.toLowerCase()
.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;
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)
@@ -506,7 +417,7 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
closingCommit = {
hash: closingHashComment.exec((timelineEvent as any).body)![1],
timestamp: +new Date(timelineEvent.created_at),
};
}
}
if (
timelineEvent.event === 'cross-referenced' &&
@@ -515,7 +426,7 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
`/${this.params.owner}/${this.params.repo}/`.toLowerCase(),
)
) {
crossReferencing.push((timelineEvent as any).source.issue.number);
crossReferencing.push((timelineEvent as any).source.issue.number)
}
}
}
@@ -526,19 +437,19 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
for (const id of crossReferencing.reverse()) {
const closed = await new OctoKitIssue(this.token, this.params, {
number: id,
}).getClosingInfo(alreadyChecked);
}, this.options).getClosingInfo(alreadyChecked)
if (closed) {
if (Math.abs(closed.timestamp - ((await this.getIssue()).closedAt ?? 0)) < 5000) {
closingCommit = closed;
break;
closingCommit = closed
break
}
}
}
}
safeLog(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`);
return closingCommit;
console.log(`Got ${JSON.stringify(closingCommit)} as closing commit of ${this.issueData.number}`)
return closingCommit
}
}
@@ -553,7 +464,7 @@ function isIssue(object: any): object is Issue {
'number' in object &&
'numComments' in object &&
'reactions' in object &&
'milestoneId' in object;
'milestoneId' in object
return isIssue;
return isIssue
}
+29 -44
View File
@@ -11,50 +11,51 @@ 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');
this.token = utils_1.getRequiredInput('token');
this.username = new github_1.GitHub(this.token).users.getAuthenticated().then((v) => v.data.name);
}
async run() {
var _a, _b, _c, _d, _e, _f;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
console.log('running ', this.id, 'with context', {
...github_1.context,
payload: {
issue: (_b = (_a = github_1.context.payload) === null || _a === void 0 ? void 0 : _a.issue) === null || _b === void 0 ? void 0 : _b.number,
label: (_d = (_c = github_1.context.payload) === null || _c === void 0 ? void 0 : _c.label) === null || _d === void 0 ? void 0 : _d.name,
repository: (_f = (_e = github_1.context.payload) === null || _e === void 0 ? void 0 : _e.repository) === null || _f === void 0 ? void 0 : _f.html_url,
sender: (_j = (_h = (_g = github_1.context.payload) === null || _g === void 0 ? void 0 : _g.sender) === null || _h === void 0 ? void 0 : _h.login) !== null && _j !== void 0 ? _j : (_l = (_k = github_1.context.payload) === null || _k === void 0 ? void 0 : _k.sender) === null || _l === void 0 ? void 0 : _l.type,
},
});
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');
((_m = github_1.context.payload.issue) === null || _m === void 0 ? void 0 : _m.number) === issue) {
return console.log('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;
const token = utils_1.getRequiredInput('token');
const readonly = !!core_1.getInput('readonly');
const issue = (_o = github_1.context === null || github_1.context === void 0 ? void 0 : github_1.context.issue) === null || _o === void 0 ? void 0 : _o.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);
await this.onCommented(octokit, github_1.context.payload.comment.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') {
else if (github_1.context.eventName === 'issues') {
switch (github_1.context.payload.action) {
case 'opened':
case 'ready_for_review':
await this.onOpened(octokit, github_1.context.payload);
await this.onOpened(octokit);
break;
case 'reopened':
await this.onReopened(octokit);
break;
case 'closed':
await this.onClosed(octokit, github_1.context.payload);
await this.onClosed(octokit);
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;
@@ -69,32 +70,22 @@ class 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));
}
await this.error(e);
}
const usage = await (0, utils_1.getRateLimit)(this.token);
const usage = await 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)
if (github_1.context.issue.number)
details.issue = github_1.context.issue.number;
const rendered = `
Message: ${details.message}
@@ -103,34 +94,28 @@ Actor: ${details.user}
ID: ${details.id}
`;
await (0, utils_1.logErrorToIssue)(rendered, true, this.token);
(0, core_1.setFailed)(error.message);
await utils_1.logErrorToIssue(rendered, true, this.token);
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) {
async onUnassigned(_issue, _label) {
throw Error('not implemented');
}
async onUnassigned(_issue, _assignee) {
throw Error('not implemented');
}
async onOpened(_issue, _payload) {
async onOpened(_issue) {
throw Error('not implemented');
}
async onReopened(_issue) {
throw Error('not implemented');
}
async onClosed(_issue, _payload) {
async onClosed(_issue) {
throw Error('not implemented');
}
async onMilestoned(_issue) {
+61 -82
View File
@@ -3,102 +3,87 @@
* 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';
import { OctoKit, OctoKitIssue, getNumRequests } from '../api/octokit'
import { context, GitHub } from '@actions/github'
import { getRequiredInput, logErrorToIssue, getRateLimit, errorLoggingIssue } from './utils'
import { getInput, setFailed } from '@actions/core'
export abstract class Action {
abstract id: string;
abstract id: string
private username: Promise<string>;
private token = getRequiredInput('token');
private username: Promise<string>
private token = getRequiredInput('token')
constructor() {
this.username = getOctokit(this.token)
.rest.users.getAuthenticated()
.then(
(v) => v.data.name ?? 'unknown',
() => 'unknown',
);
this.username = new GitHub(this.token).users.getAuthenticated().then((v) => v.data.name)
}
public async run() {
console.log('running ', this.id, 'with context', {
...context,
payload: {
issue: context.payload?.issue?.number,
label: context.payload?.label?.name,
repository: context.payload?.repository?.html_url,
sender: context.payload?.sender?.login ?? context.payload?.sender?.type,
},
})
if (errorLoggingIssue) {
const { repo, issue, owner } = 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');
return console.log('refusing to run on error logging issue to prevent cascading errors')
}
}
try {
const token = getRequiredInput('token');
const readonly = !!getInput('readonly');
const token = getRequiredInput('token')
const readonly = !!getInput('readonly')
const issue = context?.issue?.number;
const issue = context?.issue?.number
if (issue) {
const octokit = new OctoKitIssue(token, context.repo, { number: issue }, { readonly });
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'
) {
await this.onCommented(octokit, context.payload.comment.body, context.actor)
} else if (context.eventName === 'issues') {
switch (context.payload.action) {
case 'opened':
case 'ready_for_review':
await this.onOpened(octokit, context.payload);
break;
await this.onOpened(octokit)
break
case 'reopened':
await this.onReopened(octokit);
break;
await this.onReopened(octokit)
break
case 'closed':
await this.onClosed(octokit, context.payload);
break;
await this.onClosed(octokit)
break
case 'labeled':
await this.onLabeled(octokit, context.payload.label.name);
break;
case 'assigned':
await this.onAssigned(octokit, context.payload.assignee.login);
break;
await this.onLabeled(octokit, context.payload.label.name)
break
case 'unassigned':
await this.onUnassigned(octokit, context.payload.assignee.login);
break;
await this.onUnassigned(octokit, context.payload.assignee.login)
break
case 'edited':
await this.onEdited(octokit);
break;
await this.onEdited(octokit)
break
case 'milestoned':
await this.onMilestoned(octokit);
break;
await this.onMilestoned(octokit)
break
default:
throw Error('Unexpected action: ' + context.payload.action);
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 }));
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));
}
await this.error(e)
}
const usage = await getRateLimit(this.token);
const usage = await getRateLimit(this.token)
}
private async error(error: Error) {
@@ -106,9 +91,9 @@ export abstract class Action {
message: `${error.message}\n${error.stack}`,
id: this.id,
user: await this.username,
};
}
if (context.issue?.number) details.issue = context.issue.number;
if (context.issue.number) details.issue = context.issue.number
const rendered = `
Message: ${details.message}
@@ -116,43 +101,37 @@ Message: ${details.message}
Actor: ${details.user}
ID: ${details.id}
`;
await logErrorToIssue(rendered, true, this.token);
`
await logErrorToIssue(rendered, true, this.token)
setFailed(error.message);
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');
throw Error('not implemented')
}
protected async onEdited(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
throw Error('not implemented')
}
protected async onLabeled(_issue: OctoKitIssue, _label: string): Promise<void> {
throw Error('not implemented');
throw Error('not implemented')
}
protected async onAssigned(_issue: OctoKitIssue, _assignee: string): Promise<void> {
throw Error('not implemented');
protected async onUnassigned(_issue: OctoKitIssue, _label: 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 onOpened(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented')
}
protected async onReopened(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
throw Error('not implemented')
}
protected async onClosed(_issue: OctoKitIssue, _payload: WebhookPayload): Promise<void> {
throw Error('not implemented');
protected async onClosed(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented')
}
protected async onMilestoned(_issue: OctoKitIssue): Promise<void> {
throw Error('not implemented');
throw Error('not implemented')
}
protected async onCommented(_issue: OctoKitIssue, _comment: string, _actor: string): Promise<void> {
throw Error('not implemented');
throw Error('not implemented')
}
}
+180 -182
View File
@@ -1,183 +1,181 @@
"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;
"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;
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;
console.log(`labels: ${this.labels}`);
console.log(`milestoneName: ${this.milestoneName}`);
console.log(`milestoneId: ${this.milestoneId}`);
console.log(`ignoreLabels: ${this.ignoreLabels}`);
console.log(`ignoreMilestoneNames: ${this.ignoreMilestoneNames}`);
console.log(`ignoreMilestoneIds: ${this.ignoreMilestoneIds}`);
console.log(`minimumVotes: ${this.minimumVotes}`);
console.log(`maximumVotes: ${this.maximumVotes}`);
console.log(`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) {
if (this.ignoreAllWithLabels) {
// Validate that the issue does not have labels
if (issue.labels && issue.labels.length !== 0) {
console.log(`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) {
console.log(`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)) {
console.log(`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)) {
console.log(`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.milestoneId != null) {
console.log(`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 != undefined && issue.milestoneId != +this.milestoneId) {
console.log(`Issue ${issue.number} skipped due to not having required milsetone id ${this.milestoneId}. Had: ${issue.milestoneId}`);
return false;
}
// Make sure a milestones we wanted to ignore is not present.
if (issue.milestoneId != null) {
for (const str of this.ignoreMilestoneIdsSet) {
if (issue.milestoneId == +str) {
console.log(`Issue ${issue.number} skipped due to milestone ${issue.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) {
console.log(`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) {
console.log(`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
+22 -23
View File
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { Issue } from '../api/api'
import { safeLog } from './utils';
export class ActionBase {
constructor(
@@ -30,15 +29,15 @@ export class ActionBase {
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}`);
console.log(`labels: ${this.labels}`);
console.log(`milestoneName: ${this.milestoneName}`);
console.log(`milestoneId: ${this.milestoneId}`);
console.log(`ignoreLabels: ${this.ignoreLabels}`);
console.log(`ignoreMilestoneNames: ${this.ignoreMilestoneNames}`);
console.log(`ignoreMilestoneIds: ${this.ignoreMilestoneIds}`);
console.log(`minimumVotes: ${this.minimumVotes}`);
console.log(`maximumVotes: ${this.maximumVotes}`);
console.log(`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.
@@ -118,18 +117,18 @@ export class ActionBase {
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.`);
console.log(`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.`);
console.log(`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.`);
console.log(`Issue ${issue.number} skipped due to not having a required label set.`);
return false;
}
}
@@ -137,7 +136,7 @@ export class ActionBase {
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}`);
console.log(`Issue ${issue.number} skipped due to having an ignore label set: ${str}`);
return false;
}
}
@@ -145,21 +144,21 @@ export class ActionBase {
}
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.`);
if (issue.milestoneId != null) {
console.log(`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}`);
if (this.milestoneId != undefined && issue.milestoneId != +this.milestoneId) {
console.log(`Issue ${issue.number} skipped due to not having required milsetone id ${this.milestoneId}. Had: ${issue.milestoneId}`);
return false;
}
// Make sure a milestones we wanted to ignore is not present.
if (issue.milestone && issue.milestone.milestoneId != null) {
if (issue.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.`);
if (issue.milestoneId == +str) {
console.log(`Issue ${issue.number} skipped due to milestone ${issue.milestoneId} found in list of ignored milestone IDs.`);
return false;
}
}
@@ -172,14 +171,14 @@ export class ActionBase {
}
if (this.minimumVotes != undefined) {
if (upvotes < this.minimumVotes) {
safeLog(`Issue ${issue.number} skipped due to not having at least ${this.minimumVotes} upvotes. Had: ${upvotes}`);
console.log(`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}`);
console.log(`Issue ${issue.number} skipped due to having more than ${this.maximumVotes} upvotes. Had: ${upvotes}`);
return false;
}
}
-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'];
+18 -38
View File
@@ -4,16 +4,14 @@
* 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;
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) => {
exports.getInput = (name) => core.getInput(name) || undefined;
exports.getRequiredInput = (name) => core.getInput(name, { required: true });
exports.normalizeIssue = (issue) => {
let { body, title } = issue;
body = body !== null && body !== void 0 ? body : '';
title = title !== null && title !== void 0 ? title : '';
@@ -45,36 +43,25 @@ const normalizeIssue = (issue) => {
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;
exports.loadLatestRelease = async (quality) => (await axios_1.default.get(`https://vscode-update.azurewebsites.net/api/update/darwin/${quality}/latest`)).data;
exports.daysAgoToTimestamp = (days) => +new Date(Date.now() - days * 24 * 60 * 60 * 1000);
exports.daysAgoToHumanReadbleDate = (days) => new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '');
exports.getRateLimit = async (token) => {
const usageData = (await new github_1.GitHub(token).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);
}
usage[category] = 1 - usageData[category].remaining / usageData[category].limit;
});
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 };
if (repo === 'microsoft/vscode-cpptools') {
return { repo: 'vscode-cpptools', owner: 'Microsoft', issue: 6282 };
}
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 if (exports.getInput('errorLogIssueNumber')) {
return { ...github_1.context.repo, issue: +exports.getRequiredInput('errorLogIssueNumber') };
}
else {
return undefined;
@@ -85,20 +72,19 @@ exports.errorLoggingIssue = (() => {
return undefined;
}
})();
const logErrorToIssue = async (message, ping, token) => {
var _a;
exports.logErrorToIssue = async (message, ping, token) => {
// 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 })
return console.log('no error logging repo defined. swallowing error:', message);
return new octokit_1.OctoKitIssue(token, { owner: dest.owner, repo: dest.repo }, { number: dest.issue }, { readonly: !!exports.getInput('readonly') })
.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}
Issue: ${ping ? `${github_1.context.repo.owner}/${github_1.context.repo.repo}#` : ''}${github_1.context.issue.number}
Repo: ${github_1.context.repo.owner}/${github_1.context.repo.repo}
@@ -110,10 +96,4 @@ ${JSON.stringify(github_1.context, null, 2)
-->
`);
};
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
+47 -57
View File
@@ -3,24 +3,24 @@
* 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';
import * as core from '@actions/core'
import { context, GitHub } 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 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
}): { 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);
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);
body.includes('feature_request_template') || /Issue Type:.*Feature Request.*/.test(body)
const cleanse = (str: string) => {
let out = str
@@ -34,83 +34,78 @@ export const normalizeIssue = (issue: {
.replace(/does this issue occur when all extensions are disabled.*/gu, '')
.replace(/!?\[[^\]]*\]\([^)]*\)/gu, '')
.replace(/\s+/gu, ' ')
.replace(/```[^`]*?```/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);
out = out.slice(0, out.indexOf('<details>')) + out.slice(out.indexOf(`</details>`) + 10)
}
return out;
};
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;
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;
(await axios.get(`https://vscode-update.azurewebsites.net/api/update/darwin/${quality}/latest`)).data
export const daysAgoToTimestamp = (days: number): number =>
+new Date(Date.now() - days * 24 * 60 * 60 * 1000);
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$/, '');
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;
};
const usageData = (await new GitHub(token).rateLimit.get()).data.resources
const usage = {} as { core: number; graphql: number; search: number }
;(['core', 'graphql', 'search'] as const).forEach(async (category) => {
usage[category] = 1 - usageData[category].remaining / usageData[category].limit
})
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 };
const repo = context.repo.owner.toLowerCase() + '/' + context.repo.repo.toLowerCase()
if (repo === 'microsoft/vscode-cpptools') {
return { repo: 'vscode-cpptools', owner: 'Microsoft', issue: 6282 }
} else if (getInput('errorLogIssueNumber')) {
return { ...context.repo, issue: +getRequiredInput('errorLogIssueNumber') };
return { ...context.repo, issue: +getRequiredInput('errorLogIssueNumber') }
} else {
return undefined;
return undefined
}
} catch (e) {
console.error(e);
return undefined;
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.');
await new Promise((resolve) => setTimeout(resolve, 10000))
const dest = errorLoggingIssue
if (!dest) return console.log('no error logging repo defined. swallowing error:', message)
return new OctoKitIssue(token, { owner: dest.owner, repo: dest.repo }, { number: dest.issue })
return new OctoKitIssue(token, { owner: dest.owner, repo: dest.repo }, { number: dest.issue }, { readonly: !!getInput('readonly') })
.postComment(`
Workflow: ${context.workflow}
Error: ${message}
Issue: ${ping ? `${context.repo.owner}/${context.repo.repo}#` : ''}${context.issue?.number}
Issue: ${ping ? `${context.repo.owner}/${context.repo.repo}#` : ''}${context.issue.number}
Repo: ${context.repo.owner}/${context.repo.repo}
@@ -120,10 +115,5 @@ ${JSON.stringify(context, null, 2)
.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));
};
`)
}
+1221 -5909
View File
File diff suppressed because it is too large Load Diff
+5 -31
View File
@@ -10,38 +10,12 @@
"keywords": [],
"author": "",
"dependencies": {
"@actions/core": "^2.0.3",
"@actions/github": "^8.0.1",
"@octokit/rest": "^21.1.1",
"@slack/web-api": "^6.9.1",
"applicationinsights": "^2.5.1",
"axios": "^1.15.0",
"uuid": "^8.3.2"
"@actions/core": "^1.2.6",
"@actions/github": "^2.1.1",
"axios": "^0.21.1"
},
"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"
},
"overrides": {
"serialize-javascript": "^7.0.5",
"flatted": "^3.4.2",
"fast-xml-parser": "^5.5.7"
"eslint": "^6.8.0",
"typescript": "^3.8.3"
}
}
-1
View File
@@ -6,7 +6,6 @@
"moduleResolution": "node",
"removeComments": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"lib": [
"es2020"
-33
View File
@@ -1,33 +0,0 @@
name: Bug - debugger
on:
schedule:
- cron: 50 12 * * * # Run at 12:50 PM UTC (4:50 AM PST, 5:50 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Add Comment
uses: ./.github/actions/AddComment
with:
readonly: ${{ github.event.inputs.readonly }}
labels: bug,debugger
ignoreLabels: "investigate: costing,investigate,external,by design,question,more info needed,Language Service,internal"
createdAfter: "2024-07-22"
addComment: "Thank you for reporting this issue. Well let you know if we need more information to investigate it. Additionally, if you're working with GDB/LLDB, please note that the code is open source at https://github.com/microsoft/MIEngine/wiki/Contributing-Code . Your contributions are always welcome and appreciated."
addLabels: help wanted
@@ -1,24 +1,19 @@
name: By Design closer - debugger
on:
schedule:
- cron: 0 13 * * * # Run at 1:00 PM UTC (5:00 AM PST, 6:00 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,7 +21,6 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: by design,debugger
ignoreLabels: Language Service,internal
ignoreLabels: language service,internal
closeDays: 0
closeComment: "This issue has been closed because the described behavior was determined to be by design."
closeComment: "This issue has been closed automatically because it's labeled as 'by design'."
+2 -8
View File
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -28,7 +23,6 @@ jobs:
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."
closeComment: "This issue has been closed automatically because it's labeled as 'by design' 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 it is no longer relevant."
+55 -17
View File
@@ -1,17 +1,55 @@
name: CI (Linux)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: ubuntu-24.04
platform: linux
name: CI (Linux)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14.16.x
uses: actions/setup-node@v1
with:
node-version: 14.16.x
- name: Install Dependencies
run: yarn install
working-directory: Extension
- name: Generate hashes for runtime dependency packages
run: yarn run generatePackageHashes
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Validate Extension/package.json
run: yarn run pr-check
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
uses: GabrielBB/[email protected]
with:
run: yarn run unitTests
working-directory: Extension
- name: Run languageServer integration tests
uses: GabrielBB/[email protected]
with:
run: yarn run integrationTests
working-directory: Extension
+55 -18
View File
@@ -1,18 +1,55 @@
name: CI (Mac)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: macos-15
platform: mac
yarn-args: --network-timeout 100000
name: CI (Mac)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14.16.x
uses: actions/setup-node@v1
with:
node-version: 14.16.x
- name: Install Dependencies
run: yarn install --network-timeout 100000
working-directory: Extension
- name: Generate hashes for runtime dependency packages
run: yarn run generatePackageHashes
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Validate Extension/package.json
run: yarn run pr-check
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
uses: GabrielBB/[email protected]
with:
run: yarn run unitTests
working-directory: Extension
- name: Run languageServer integration tests
uses: GabrielBB/[email protected]
with:
run: yarn run integrationTests
working-directory: Extension
+51 -17
View File
@@ -1,17 +1,51 @@
name: CI (Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: windows-2025
platform: windows
name: CI (Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 14.16.x
uses: actions/setup-node@v1
with:
node-version: 14.16.x
- name: Install Dependencies
run: yarn install
working-directory: Extension
- name: Generate hashes for runtime dependency packages
run: yarn run generatePackageHashes
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Validate Extension/package.json
run: yarn run pr-check
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
run: yarn run unitTests
working-directory: Extension
- name: Run languageServer integration tests
run: yarn run integrationTests
working-directory: Extension
-97
View File
@@ -1,97 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "main", "insiders", "release", "vs" ]
pull_request:
branches: [ "main", "insiders", "release", "vs" ]
schedule:
- cron: '29 4 * * 3'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v5
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
+2 -8
View File
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -28,7 +23,6 @@ jobs:
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."
closeComment: "This issue has been closed automatically because it's labeled as a 'duplicate' 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 it is no longer relevant."
@@ -1,24 +1,19 @@
name: Enhancement Closer (no milestone)
on:
schedule:
- cron: 40 12 * * * # Run at 12:40 PM UTC (4:40 AM PST, 5:40 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -30,7 +25,6 @@ jobs:
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."
closeComment: "This feature request is being closed due to insufficient upvotes. When enough upvotes are received, this issue will be eligible for our backlog."
setMilestoneId: 30
ignoreMilestoneNames: "*"
@@ -1,24 +1,19 @@
name: Enhancement Closer (Triage)
on:
schedule:
- cron: 30 12 * * * # Run at 12:30 PM UTC (4:30 AM PST, 5:30 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -30,7 +25,6 @@ jobs:
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."
closeComment: "This feature request is being closed due to insufficient upvotes. When enough upvotes are received, this issue will be eligible for our backlog."
milestoneName: Triage
milestoneId: 30
+2 -8
View File
@@ -1,24 +1,19 @@
name: Enhancement Reopener
on:
schedule:
- cron: 0 11 * * * # Run at 11:00 AM UTC (3:00 AM PST, 4:00 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Reopener
@@ -34,4 +29,3 @@ jobs:
milestoneName: Triage
setMilestoneId: 28
removeLabels: more votes needed
+4 -10
View File
@@ -1,24 +1,19 @@
name: External closer - debugger
on:
schedule:
- cron: 10 13 * * * # Run at 1:10 PM UTC (5:10 AM PST, 6:10 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,7 +21,6 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: external,debugger
ignoreLabels: Language Service,internal
ignoreLabels: language service,internal
closeDays: 0
closeComment: "This issue has been closed because it is external or not applicable to the extension."
closeComment: "This issue has been closed automatically because it's labeled as 'external'."
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -30,7 +25,6 @@ jobs:
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."
closeComment: "This feature request is being closed due to insufficient upvotes. When enough upvotes are received, this issue will be eligible for our backlog."
setMilestoneId: 30
ignoreMilestoneNames: "*"
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -30,7 +25,6 @@ jobs:
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."
closeComment: "This feature request is being closed due to insufficient upvotes. When enough upvotes are received, this issue will be eligible for our backlog."
milestoneName: Triage
milestoneId: 30
@@ -1,33 +0,0 @@
name: Feature Request - debugger
on:
schedule:
- cron: 20 13 * * * # Run at 1:20 PM UTC (5:20 AM PST, 6:20 AM PDT)
workflow_dispatch:
inputs:
readonly:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Add Comment
uses: ./.github/actions/AddComment
with:
readonly: ${{ github.event.inputs.readonly }}
labels: Feature Request,debugger
ignoreLabels: "investigate: costing,investigate,external,by design,question,more info needed,Language Service,internal"
createdAfter: "2024-07-22"
addComment: "Thank you for your feature request. While we may not be able to implement it immediately, we will monitor community reactions to see how it fits into our backlog. Additionally, if you're working with GDB/LLDB, please note that the code is open source at https://github.com/microsoft/MIEngine/wiki/Contributing-Code . Your contributions are always welcome and appreciated."
addLabels: help wanted
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Reopener
@@ -34,4 +29,3 @@ jobs:
milestoneName: Triage
setMilestoneId: 28
removeLabels: more votes needed
@@ -1,24 +1,19 @@
name: Investigate closer - debugger
on:
schedule:
- cron: 30 13 * * * # Run at 1:30 PM UTC (5:30 AM PST, 6:30 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,7 +21,6 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: investigate,debugger
ignoreLabels: Language Service,internal
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."
closeComment: "This issue has been closed automatically because it has not had recent activity."
@@ -1,24 +1,19 @@
name: Investigate Costing closer - debugger
on:
schedule:
- cron: 40 13 * * * # Run at 1:40 PM UTC (5:40 AM PST, 6:40 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,7 +21,6 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: "investigate: costing,debugger"
ignoreLabels: Language Service,internal
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."
closeComment: "This issue has been closed automatically because it has not had recent activity."
@@ -1,97 +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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
build:
runs-on: ${{ inputs.runner-env }}
steps:
- uses: actions/checkout@v5
- name: Use Node.js 24
uses: actions/setup-node@v4
with:
node-version: 24
- 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
# These tests don't require the binary.
# On Linux, it is failing (before the tests actually run) with: Test run terminated with signal SIGSEGV.
# But it works on Linux during the E2E test.
- name: Run SingleRootProject tests
if: ${{ inputs.platform != 'linux' }}
run: yarn test --scenario=SingleRootProject --skipCheckBinaries
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
# - name: Run E2E IntelliSense features tests
# if: ${{ inputs.platform == 'windows' }}
# run: yarn test --scenario=RunWithoutDebugging
# 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
# - name: Run E2E IntelliSense features tests (xvfb)
# if: ${{ inputs.platform == 'mac' || inputs.platform == 'linux' }}
# uses: coactions/setup-xvfb@v1
# with:
# run: yarn test --scenario=RunWithoutDebugging
# working-directory: Extension
+1 -7
View File
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Run Locker
@@ -28,4 +23,3 @@ jobs:
daysSinceClose: 45
daysSinceUpdate: 3
ignoreLabels: more votes needed,debugger,internal
@@ -1,24 +1,19 @@
name: More Info Needed Closer - debugger
on:
schedule:
- cron: 50 13 * * * # Run at 1:50 PM UTC (5:50 AM PST, 6:50 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,10 +21,9 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: more info needed,debugger
ignoreLabels: Language Service,internal
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."
closeComment: "This issue has been closed automatically 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."
+4 -10
View File
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -27,8 +22,7 @@ jobs:
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
closeDays: 60
closeComment: "This issue has been closed automatically because it needs more information 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 problem no longer exists, or adding more information."
+4 -10
View File
@@ -1,24 +1,19 @@
name: Question Closer - debugger
on:
schedule:
- cron: 0 14 * * * # Run at 2:00 PM UTC (6:00 AM PST, 7:00 AM PDT)
- 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
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -26,10 +21,9 @@ jobs:
with:
readonly: ${{ github.event.inputs.readonly }}
labels: question,debugger
ignoreLabels: Language Service,internal
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."
closeComment: "This issue has been closed automatically because it's labeled as 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."
+2 -8
View File
@@ -8,17 +8,12 @@ on:
description: "readonly: Specify true or 1 to prevent changes from being commited to GitHub"
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
main:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v2
- name: Install Actions
run: cd ./.github/actions && npm install --production && cd ../..
- name: Stale Closer
@@ -28,7 +23,6 @@ jobs:
labels: question
ignoreLabels: debugger,internal
closeDays: 60
closeComment: "This issue has been closed because it is a question and has not had recent activity."
closeComment: "This issue has been closed automatically because it's labeled as 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
View File
@@ -9,7 +9,6 @@ browse*.db*
# ignore exported localization xlf and LCL directories
Build/loc/LCL
vscode-extensions-localization-export
OneLocBuild
# ignore imported localization xlf directory
vscode-translations-import
-120
View File
@@ -1,120 +0,0 @@
name: $(date:yyyyMMdd)$(rev:.r)
trigger:
branches:
include:
- main
- release
- insiders
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: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
binskim:
preReleaseVersion: '4.3.1'
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
settings:
networkIsolationPolicy: Permissive,CFSClean,CFSClean2,CFSClean3
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: UseNode@1
displayName: Use Node 22.x
inputs:
version: 22.x
- script: IF EXIST %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc del %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc
displayName: Delete .npmrc if it exists
- script: mkdir $(Build.ArtifactStagingDirectory)\Extension
displayName: Create Extension Staging Directory
- task: Bash@3
displayName: Build files
inputs:
targetType: 'inline'
script: |
export SRC_DIR=$(echo $BUILD_SOURCESDIRECTORY | sed 's|\\|/|g')
cd "$SRC_DIR/Extension"
npm run vsix-prepublish
if [ $? -ne 0 ]; then
echo "npm run vsix-prepublish failed, sleeping for 30s before retrying..."
sleep 30
exit 1
fi
retryCountOnTaskFailure: 3
- script: yarn install --frozen-lockfile
displayName: Install dependencies with yarn
workingDirectory: $(Build.SourcesDirectory)\Extension
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
displayName: Verify vsce-sign binary exists
workingDirectory: $(Build.SourcesDirectory)\Extension
- script: npx vsce package --yarn -o $(Build.ArtifactStagingDirectory)\Extension\cpptools.vsix
displayName: Run VSCE to package vsix
workingDirectory: $(Build.SourcesDirectory)\Extension
-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()
+127 -21
View File
@@ -1,23 +1,129 @@
parameters:
- name: Build_Type
displayName: Build Type
type: string
default: Release
variables:
llvm_repo: https://github.com/llvm/llvm-project.git
llvm_branch: release/12.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: dev/waan/testLLDB12x # TODO: Change to main
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
}
# Don't use XCode CLI since it will cause C++ headers to be missing.
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 $(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'
+31 -68
View File
@@ -2,14 +2,11 @@
# Pipeline for VsCodeExtension-Localization build definition
# Runs OneLocBuild task to localize xlf file
# ==================================================================================
resources:
repositories:
- repository: self
clean: true
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
trigger: none
pr: none
@@ -21,72 +18,38 @@ schedules:
- main
always: true
variables:
TeamName: cpptools
Codeql.Language: javascript
pool:
vmImage: 'windows-latest'
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
stages:
- stage: stage
jobs:
- job: job
templateContext:
outputs:
- output: pipelineArtifact
targetPath: '$(Build.ArtifactStagingDirectory)'
artifactName: 'drop'
publishLocation: 'Container'
steps:
- task: NodeTool@0
inputs:
versionSpec: '22.x'
displayName: 'Install Node.js'
steps:
- task: CmdLine@2
inputs:
script: 'cd Extension && yarn install'
- task: CmdLine@2
inputs:
script: 'cd Extension && yarn install'
- task: CmdLine@2
inputs:
script: 'cd ./Extension && yarn run translations-export && cd ..'
- 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'
# Requires Azure client 2.x
- task: AzureCLI@2
displayName: 'Set OneLocBuildToken'
enabled: true
inputs:
azureSubscription: '$(AzureSubscription)' # Azure DevOps service connection
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$token = az account get-access-token --query accessToken --resource $(AzureGuid) -o tsv
Write-Host "##vso[task.setvariable variable=AzDO.OneLocBuildToken;issecret=true]${token}"
- 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: OneLocBuild@2
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
locProj: 'Build/loc/LocProject.json'
outDir: '$(Build.ArtifactStagingDirectory)'
isCreatePrSelected: false
prSourceBranchPrefix: 'locfiles'
packageSourceAuth: 'patAuth'
patVariable: '$(AzDO.OneLocBuildToken)'
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'
-50
View File
@@ -1,50 +0,0 @@
name: $(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
parameters:
- name: verifyVersion
displayName: Attest version in package.json is correct
type: boolean
default: false
- name: verifyReadme
displayName: Attest README.md is updated
type: boolean
default: false
resources:
repositories:
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
settings:
networkIsolationPolicy: Permissive,CFSClean,CFSClean2,CFSClean3
stages:
- stage: package
jobs:
# Introduce pipeline compilation errors to block scheduling if the requisite parameters are not set
- ${{ if not(eq(parameters.verifyVersion, true)) }}:
- 'The version in package.json should be updated before scheduling the pipeline.'
- ${{ if not(eq(parameters.verifyReadme, true)) }}:
- 'README.md should be updated before scheduling the pipeline.'
- template: /Build/package/jobs_package_vsix.yml@self
parameters:
vsixName: cpptools-extension-pack
srcDir: ExtensionPack
-50
View File
@@ -1,50 +0,0 @@
name: $(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
parameters:
- name: verifyVersion
displayName: Attest version in package.json is correct
type: boolean
default: false
- name: verifyReadme
displayName: Attest README.md is updated
type: boolean
default: false
resources:
repositories:
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
settings:
networkIsolationPolicy: Permissive,CFSClean,CFSClean2,CFSClean3
stages:
- stage: package
jobs:
# Introduce pipeline compilation errors to block scheduling if the requisite parameters are not set
- ${{ if not(eq(parameters.verifyVersion, true)) }}:
- 'The version in package.json should be updated before scheduling the pipeline.'
- ${{ if not(eq(parameters.verifyReadme, true)) }}:
- 'README.md should be updated before scheduling the pipeline.'
- template: /Build/package/jobs_package_vsix.yml@self
parameters:
vsixName: cpptools-themes
srcDir: Themes
-95
View File
@@ -1,95 +0,0 @@
parameters:
- name: vsixName
type: string
default: ''
- name: srcDir
type: string
default: ''
- name: signType
type: string
default: 'real'
jobs:
- job: package
displayName: Build ${{ parameters.vsixName }}.vsix
timeoutInMinutes: 30
cancelTimeoutInMinutes: 1
templateContext:
mb: # Enable the MicroBuild Signing toolset
signing:
enabled: true
signType: ${{ parameters.signType }}
zipSources: false
${{ if eq(parameters.signType, 'real') }}:
signWithProd: true
featureFlags:
autoBaseline: false
outputs:
- output: pipelineArtifact
displayName: '${{ parameters.vsixName }}.vsix'
targetPath: $(Build.ArtifactStagingDirectory)\vsix
artifactName: vsix
steps:
- checkout: self
- task: UseNode@1
displayName: Use Node 22.x
inputs:
version: 22.x
- script: IF EXIST %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc del %SYSTEMDRIVE%\Users\%USERNAME%\.npmrc
displayName: Delete .npmrc if it exists
- task: Bash@3
displayName: Build files
inputs:
targetType: 'inline'
script: |
export SRC_DIR=$(echo $BUILD_SOURCESDIRECTORY | sed 's|\\|/|g')
cd "$SRC_DIR/${{ parameters.srcDir }}"
npm install
if [ $? -ne 0 ]; then
echo "npm install failed, sleeping for 30s before retrying..."
sleep 30
exit 1
fi
retryCountOnTaskFailure: 3
- script: mkdir $(Build.ArtifactStagingDirectory)\vsix
displayName: Create Staging Directory
- script: npm install --no-save --ignore-scripts=false --include=optional --force @vscode/[email protected]
displayName: Install vsce
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
- script: npm rebuild @vscode/vsce-sign --ignore-scripts=false
displayName: Rebuild vsce-sign binary
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
displayName: Verify vsce-sign binary exists
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
- script: npx vsce package -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix
displayName: Run VSCE to package vsix
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
# sign the vsix
- script: npx vsce generate-manifest -i $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.manifest
displayName: generate manifest
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
- script: copy $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.manifest $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.signature.p7s
displayName: prepare manifest for signing
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
- task: NuGetToolInstaller@1
displayName: Install NuGet
- task: NuGetAuthenticate@1
displayName: Authenticate NuGet
- script: nuget restore $(Build.SourcesDirectory)\Build\signing\SignVsix.proj -PackagesDirectory $(Build.SourcesDirectory)\Build\signing\packages -ConfigFile $(Build.SourcesDirectory)\Build\signing\NuGet.config
displayName: Restore MicroBuild Core
- task: MSBuild@1
displayName: Sign the vsix
inputs:
solution: $(Build.SourcesDirectory)\Build\signing\SignVsix.proj
msbuildArguments: /p:SignType=${{ parameters.signType }}
-43
View File
@@ -1,43 +0,0 @@
name: $(Date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
resources:
repositories:
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
pipelines:
- pipeline: vsixBuild
source: '\VC\VSCode\CpptoolsVSIX\Package cpptools-extension-pack'
trigger: true
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
stages:
- stage: Validate
jobs:
- template: /Build/publish/jobs_manual_validation.yml@self
parameters:
notifyUsers: $(NotifyUsers)
releaseBuildUrl: $(ReleaseBuildUrl)
- stage: Release
dependsOn: Validate
jobs:
- template: /Build/publish/jobs_publish_vsix.yml@self
parameters:
vsixName: cpptools-extension-pack
-43
View File
@@ -1,43 +0,0 @@
name: $(Date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
resources:
repositories:
- repository: MicroBuildTemplate
type: git
name: 1ESPipelineTemplates/MicroBuildTemplate
ref: refs/tags/release
pipelines:
- pipeline: vsixBuild
source: '\VC\VSCode\CpptoolsVSIX\Package cpptools-themes'
trigger: true
extends:
template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
sdl:
sourceAnalysisPool:
name: AzurePipelines-EO
image: 1ESPT-Windows2025
os: windows
stages:
- stage: Validate
jobs:
- template: /Build/publish/jobs_manual_validation.yml@self
parameters:
notifyUsers: $(NotifyUsers)
releaseBuildUrl: $(ReleaseBuildUrl)
- stage: Release
dependsOn: Validate
jobs:
- template: /Build/publish/jobs_publish_vsix.yml@self
parameters:
vsixName: cpptools-themes
-19
View File
@@ -1,19 +0,0 @@
parameters:
- name: notifyUsers
type: string
default: ''
- name: releaseBuildUrl
type: string
default: ''
jobs:
- job: WaitForValidation
displayName: Wait for VSIX validation
pool: server
steps:
- task: ManualValidation@0
displayName: "Manual Validation"
inputs:
notifyUsers: $(notifyUsers)
instructions: |
Download and test the vsix from the latest release build: $(releaseBuildUrl)
-46
View File
@@ -1,46 +0,0 @@
parameters:
- name: vsixName
type: string
default: ''
jobs:
- job: Publish
displayName: Publish to Marketplace
templateContext:
type: releaseJob
isProduction: true
inputs:
- input: pipelineArtifact
pipeline: vsixBuild
artifactName: vsix
targetPath: $(Build.StagingDirectory)\vsix
steps:
- task: NodeTool@0
displayName: Use Node 22.x
inputs:
versionSpec: 22.x
- task: AzureCLI@2
displayName: Generate AAD_TOKEN
inputs:
azureSubscription: $(AzureSubscription)
scriptType: ps
scriptLocation: inlineScript
inlineScript: |
$aadToken = az account get-access-token --query accessToken --resource $(AzureGuid) -o tsv
Write-Host "##vso[task.setvariable variable=AAD_TOKEN;issecret=true]$aadToken"
- script: npm install --no-save --ignore-scripts=false --include=optional --force @vscode/[email protected]
displayName: Install vsce
- script: npm rebuild @vscode/vsce-sign --ignore-scripts=false
displayName: Rebuild vsce-sign binary
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
displayName: Verify vsce-sign binary exists
- script: npx vsce publish --skip-duplicate -i $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.vsix --manifestPath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.manifest --signaturePath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.signature.p7s
displayName: Publish to Marketplace
env:
VSCE_PAT: $(AAD_TOKEN)
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="Engineering" value="https://pkgs.dev.azure.com/devdiv/_packaging/MicroBuildToolset/nuget/v3/index.json" />
</packageSources>
</configuration>
-21
View File
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="SignFiles" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Microsoft.VisualStudioEng.MicroBuild.Core.0.4.1\build\Microsoft.VisualStudioEng.MicroBuild.Core.props" />
<PropertyGroup>
<BaseOutputDirectory>$(BUILD_STAGINGDIRECTORY)/Extension</BaseOutputDirectory>
<!-- These properties are required by MicroBuild, which only signs files that are under these paths -->
<IntermediateOutputPath>$(BaseOutputDirectory)</IntermediateOutputPath>
<OutDir>$(BaseOutputDirectory)</OutDir>
</PropertyGroup>
<ItemGroup>
<!-- Because of Webpack bundling, these are the only shipping Javascript files.
There are no third-party files to sign because they've all been bundled. -->
<FilesToSign Include="$(OutDir)\dist\src\main.js;$(OutDir)\dist\ui\settings.js">
<Authenticode>Microsoft400</Authenticode>
</FilesToSign>
</ItemGroup>
<Import Project="packages\Microsoft.VisualStudioEng.MicroBuild.Core.0.4.1\build\Microsoft.VisualStudioEng.MicroBuild.Core.targets" />
</Project>
-19
View File
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="SignFiles" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Microsoft.VisualStudioEng.MicroBuild.Core.0.4.1\build\Microsoft.VisualStudioEng.MicroBuild.Core.props" />
<PropertyGroup>
<BaseOutputDirectory>$(BUILD_STAGINGDIRECTORY)</BaseOutputDirectory>
<!-- These properties are required by MicroBuild, which only signs files that are under these paths -->
<IntermediateOutputPath>$(BaseOutputDirectory)</IntermediateOutputPath>
<OutDir>$(BaseOutputDirectory)</OutDir>
</PropertyGroup>
<ItemGroup>
<FilesToSign Include="$(OutDir)\vsix\cpptools-*.signature.p7s">
<Authenticode>VSCodePublisher</Authenticode>
</FilesToSign>
</ItemGroup>
<Import Project="packages\Microsoft.VisualStudioEng.MicroBuild.Core.0.4.1\build\Microsoft.VisualStudioEng.MicroBuild.Core.targets" />
</Project>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.VisualStudioEng.MicroBuild.Core" version="0.4.1" developmentDependency="true" />
</packages>
-8
View File
@@ -1,8 +0,0 @@
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @microsoft/cpptools-maintainers will be requested for
# review when someone opens a pull request.
* @microsoft/cpptools-maintainers
+1 -2
View File
@@ -6,5 +6,4 @@ 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)
- Contact [[email protected]](mailto:[email protected]) with questions or concerns
+1 -22
View File
@@ -5,7 +5,7 @@
* [Build and debug the extension](Documentation/Building%20the%20Extension.md).
* 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/scenarios/SingleRootProject/tests/extension.test.ts).
* 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".
## About the Code
@@ -33,24 +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.
### Adding/Updating package.json dependencies
We maintain a public Azure Artifacts feed that we point the package manager to in .npmrc files. If you want to add a dependency or update a version in package.json, you may need to contact us so we can add it to our feed. Please ping our team in a PR or new issue if you experience this issue.
For local development, you can delete the .npmrc file and the matching `yarn.lock` file while you wait for us to update the feed. However, these changes will need to be reverted in your branch before we will accept a PR.
+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.
+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>
@@ -1 +1 @@
The documentation for c_cpp_properties.json has moved to https://code.visualstudio.com/docs/cpp/customize-cpp-settings.
The documentation for c_cpp_properties.json has moved to https://code.visualstudio.com/docs/cpp/c-cpp-properties-schema-reference.
+4
View File
@@ -0,0 +1,4 @@
*.js
test/**/index.ts
test/**/runTest.ts
tools/prepublish.js
+154
View File
@@ -0,0 +1,154 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"@typescript-eslint/tslint",
"eslint-plugin-jsdoc",
"@typescript-eslint/eslint-plugin-tslint",
"eslint-plugin-import",
],
"rules": {
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": "error",
"camelcase": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "typeLike",
"format": ["PascalCase"]
}
],
"@typescript-eslint/indent": "error",
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "semi",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-this-alias": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-arguments": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/semi": "error",
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
"arrow-body-style": "error",
"comma-dangle": "error",
"constructor-super": "error",
"curly": "error",
"eol-last": "error",
"eqeqeq": [
"error",
"always"
],
"import/no-default-export": "error",
"import/no-unassigned-import": "error",
"jsdoc/no-types": "error",
"new-parens": "error",
"no-bitwise": "error",
"no-caller": "error",
"no-cond-assign": "error",
"no-debugger": "error",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-eval": "error",
"no-fallthrough": "error",
"no-invalid-this": "error",
"no-irregular-whitespace": "error",
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
"no-new-wrappers": "error",
"no-redeclare": "error",
"no-return-await": "error",
"no-sequences": "error",
"no-sparse-arrays": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-var": "error",
"one-var": [
"error",
"never"
],
"prefer-const": "error",
"prefer-object-spread": "error",
"space-in-parens": [
"error",
"never"
],
"spaced-comment": [
"error",
"always"
],
"use-isnan": "error",
"valid-typeof": "error",
"yoda": "error",
"@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
@@ -10,7 +10,6 @@ server
debugAdapters
LLVM
bin/cpptools*
bin/libc.so
bin/*.dll
bin/.vs
bin/LICENSE.txt
@@ -26,6 +25,7 @@ install.lock
# ignore generated localization file
**/nls.*.json
**/*.nls.json
**/*.nls.*.json
# ignore generate native header
@@ -34,5 +34,3 @@ localized_string_ids.h
# ignore generate files. It will be generated when building
src/nativeStrings.ts
vscode*.d.ts
.scripts/_*
-4
View File
@@ -1,4 +0,0 @@
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
always-auth=true
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
ignore-scripts=true
-67
View File
@@ -1,67 +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 is string => each !== undefined && !each.includes('node_modules')));
}
export async function reset() {
verbose(`Resetting all .gitignored files in extension`);
await rimraf(...(await getModifiedIgnoredFiles()).filter((each): each is string => each !== undefined));
}
async function details(files: string[]) {
const results = await Promise.all(files.filter(each => each).map(async (each) => {
const [, stats] = await filepath.stats(each);
if (!stats) {
return null;
}
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
};
}));
let all = results.filter((each): each is NonNullable<typeof each> => each !== null);
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()).filter((each): each is string => each !== undefined));
default:
return error(`Unknown option '${opt}'`);
}
}
-42
View File
@@ -1,42 +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 ].map(each => (each.indexOf(' ') > -1) && (each.indexOf('"') === -1) ? `"${each}"` : each);
const CLI = cli.indexOf(' ') > -1 && cli.indexOf('"') === -1 ? `"${cli}"` : cli;
verbose(gray(`${CLI}\n ${ [...ARGS ].join('\n ')}`));
spawnSync(CLI, ARGS, { encoding: 'utf-8', stdio: 'ignore', env: { ...process.env, DONT_PROMPT_WSL_INSTALL:"1" }, shell: true });
}

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