Skip to content

Commit

Permalink
build: improve logic for issue template closing and add tests (#5905)
Browse files Browse the repository at this point in the history
* update bug template

* build: aimprove logic for issue template closing and add tests

* chore: akeep issue template the same

* chore: clean up scripts

* clean up scripts

* try

* update pnpm to v4

* revert accidental change

* revert broken change to generative ai

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix test

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* chore: add heap allocation max size

* revert change to publish name

* Update package.json

---------

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
sofisl and gcf-owl-bot[bot] authored Jan 16, 2025
1 parent 75e242b commit ecc4989
Show file tree
Hide file tree
Showing 17 changed files with 2,737 additions and 20 deletions.
19 changes: 12 additions & 7 deletions .github/scripts/close-invalid-link.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@ module.exports = async ({ github, context }) => {
if (isBugTemplate) {
console.log(`Issue ${number} is a bug template`)
try {
const link = issue.data.body.split("\n")[18].match(/(https?:\/\/(gist\.)?github.com\/.*)/)[0];
console.log(`Issue ${number} contains this link: ${link}`)
const isValidLink = (await fetch(link)).ok;
console.log(`Issue ${number} has a ${isValidLink ? "valid" : "invalid"} link`)
if (!isValidLink) {
await closeIssue(github, owner, repo, number);
}
const text = issue.data.body;
const match = text.match(/Link to the code that reproduces this issue. A link to a \*\*public\*\* Github Repository with a minimal reproduction/);
if (match) {
const nextLineIndex = text.indexOf('http', match.index);
const link = text.substring(nextLineIndex, text.indexOf('\n', nextLineIndex));
console.log(`Issue ${number} contains this link: ${link}`);
const isValidLink = (await fetch(link)).ok;
console.log(`Issue ${number} has a ${isValidLink ? "valid" : "invalid"} link`)
if (!isValidLink) {
await closeIssue(github, owner, repo, number);
}
}
} catch (err) {
await closeIssue(github, owner, repo, number);
}
Expand Down
45 changes: 45 additions & 0 deletions .github/scripts/close-invalid-link.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const {describe, it} = require('mocha');
const closeInvalidLink = require('./close-invalid-link.cjs');
const fs = require('fs');

describe('Quickstart', () => {
it('does not do anything if it is not a bug', async () => {
const context = {repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}}
const octokit = {rest: {issues: {get: () => {return {data: {body: "I'm having a problem with this."}}}}}};
await closeInvalidLink({github: octokit, context});
});

it('does not do anything if it is a bug with an appropriate link', async () => {
const context = {repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}}
const octokit = {rest: {issues: {get: () => {return {data: {body: fs.readFileSync('./fixtures/validIssueBody.txt', 'utf-8')}}}}}};
await closeInvalidLink({github: octokit, context});
});

it('does not do anything if it is a bug with an appropriate link and the template changes', async () => {
const context = {repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}}
const octokit = {rest: {issues: {get: () => {return {data: {body: fs.readFileSync('./fixtures/validIssueBodyDifferentLinkLocation.txt', 'utf-8')}}}}}};
await closeInvalidLink({github: octokit, context});
});

it('closes the issue if the link is invalid', async () => {
const context = {repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}}
const octokit = {rest: {issues: {get: () => {return {data: {body: fs.readFileSync('./fixtures/invalidIssueBody.txt', 'utf-8')}}}, createComment: () => {return}, update: () => {return}}}};
await closeInvalidLink({github: octokit, context});
});
});
57 changes: 57 additions & 0 deletions .github/scripts/close-or-remove-response-label.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const {describe, it} = require('mocha');
const removeResponseLabel = require('./remove-response-label.cjs');
const closeUnresponsive = require('./close-unresponsive.cjs');

function getISODateDaysAgo(days) {
const today = new Date();
const daysAgo = new Date(today.setDate(today.getDate() - days));
return daysAgo.toISOString();
}

describe('Quickstart', () => {
it('closes the issue if the OP has not responded within the allotted time and there is a needs-more-info label', async () => {
const context = {owner: 'testOrg', repo: 'testRepo'}
const issuesInRepo = [{user: {login: 'OP'}, labels: [{name: 'needs more info'}]}]
const eventsInIssue = [{event: 'labeled', label: {name: 'needs more info'}, created_at: getISODateDaysAgo(16)}];
const octokit = {rest: {issues: {listForRepo: () => {return {data: issuesInRepo}}, update: () => {return}, createComment: () => {return}}}, paginate: () => {return eventsInIssue}};
await closeUnresponsive({github: octokit, context});
});

it('does nothing if not enough time has passed and there is a needs-more-info label', async () => {
const context = {owner: 'testOrg', repo: 'testRepo'}
const issuesInRepo = [{user: {login: 'OP'}, labels: [{name: 'needs more info'}]}]
const eventsInIssue = [{event: 'labeled', label: {name: 'needs more info'}, created_at: getISODateDaysAgo(14)}];
const octokit = {rest: {issues: {listForRepo: () => {return {data: issuesInRepo}}}}, paginate: () => {return eventsInIssue}};
await closeUnresponsive({github: octokit, context});
});

it('removes the label if OP responded', async () => {
const context = {actor: 'OP', repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}};
const issueContext = {user: 'OP', login: 'OP', labels: [{name: 'needs more info'}]};
const octokit = {rest: {issues: {get: () => {return {data: issueContext}}, removeLabel: () => {return}}}};
await removeResponseLabel({github: octokit, context});
});

it('does not remove the label if author responded', async () => {
const context = {actor: 'repo-maintainer', repo: {owner: 'testOrg', repo: 'testRepo'}, issue: {number: 1}};
const issueContext = {user: 'OP', login: 'OP', labels: [{name: 'needs more info'}]};
const octokit = {rest: {issues: {get: () => {return {data: issueContext}}}}};
await removeResponseLabel({github: octokit, context});
});
});
51 changes: 51 additions & 0 deletions .github/scripts/fixtures/invalidIssueBody.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
### Please make sure you have searched for information in the following guides.

- [X] Search the issues already opened: https://github.com/GoogleCloudPlatform/google-cloud-node/issues
- [X] Search StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform+node.js
- [X] Check our Troubleshooting guide: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/troubleshooting
- [X] Check our FAQ: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/faq
- [X] Check our libraries HOW-TO: https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md
- [X] Check out our authentication guide: https://github.com/googleapis/google-auth-library-nodejs
- [X] Check out handwritten samples for many of our APIs: https://github.com/GoogleCloudPlatform/nodejs-docs-samples

### A screenshot that you have tested with "Try this API".


N/A

### Link to the code that reproduces this issue. A link to a **public** Github Repository with a minimal reproduction.


not-a-link

### A step-by-step description of how to reproduce the issue, based on the linked reproduction.


Change MY_PROJECT to your project name, add credentials if needed and run.

### A clear and concise description of what the bug is, and what you expected to happen.

The application crashes with the following exception (which there is no way to catch). It should just emit error, and allow graceful handling.
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object
at _write (node:internal/streams/writable:474:13)
at Writable.write (node:internal/streams/writable:502:10)
at Duplexify._write (/project/node_modules/duplexify/index.js:212:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at Pumpify.<anonymous> (/project/node_modules/@google-cloud/speech/build/src/helpers.js:79:27)
at Object.onceWrapper (node:events:633:26)
at Pumpify.emit (node:events:518:28)
at obj.<computed> [as _write] (/project/node_modules/stubs/index.js:28:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at PassThrough.ondata (node:internal/streams/readable:1007:22)
at PassThrough.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:559:12) {
code: 'ERR_INVALID_ARG_TYPE'


### A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **

No library should crash an application this way.
51 changes: 51 additions & 0 deletions .github/scripts/fixtures/validIssueBody.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
### Please make sure you have searched for information in the following guides.

- [X] Search the issues already opened: https://github.com/GoogleCloudPlatform/google-cloud-node/issues
- [X] Search StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform+node.js
- [X] Check our Troubleshooting guide: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/troubleshooting
- [X] Check our FAQ: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/faq
- [X] Check our libraries HOW-TO: https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md
- [X] Check out our authentication guide: https://github.com/googleapis/google-auth-library-nodejs
- [X] Check out handwritten samples for many of our APIs: https://github.com/GoogleCloudPlatform/nodejs-docs-samples

### A screenshot that you have tested with "Try this API".


N/A

### Link to the code that reproduces this issue. A link to a **public** Github Repository with a minimal reproduction.


https://gist.github.com/orgads/13cbf44c91923da27d8772b5f10489c9

### A step-by-step description of how to reproduce the issue, based on the linked reproduction.


Change MY_PROJECT to your project name, add credentials if needed and run.

### A clear and concise description of what the bug is, and what you expected to happen.

The application crashes with the following exception (which there is no way to catch). It should just emit error, and allow graceful handling.
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object
at _write (node:internal/streams/writable:474:13)
at Writable.write (node:internal/streams/writable:502:10)
at Duplexify._write (/project/node_modules/duplexify/index.js:212:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at Pumpify.<anonymous> (/project/node_modules/@google-cloud/speech/build/src/helpers.js:79:27)
at Object.onceWrapper (node:events:633:26)
at Pumpify.emit (node:events:518:28)
at obj.<computed> [as _write] (/project/node_modules/stubs/index.js:28:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at PassThrough.ondata (node:internal/streams/readable:1007:22)
at PassThrough.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:559:12) {
code: 'ERR_INVALID_ARG_TYPE'


### A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **

No library should crash an application this way.
50 changes: 50 additions & 0 deletions .github/scripts/fixtures/validIssueBodyDifferentLinkLocation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
### Please make sure you have searched for information in the following guides.

- [X] Search the issues already opened: https://github.com/GoogleCloudPlatform/google-cloud-node/issues
- [X] Search StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform+node.js
- [X] Check our Troubleshooting guide: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/troubleshooting
- [X] Check our FAQ: https://googlecloudplatform.github.io/google-cloud-node/#/docs/guides/faq
- [X] Check our libraries HOW-TO: https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md
- [X] Check out our authentication guide: https://github.com/googleapis/google-auth-library-nodejs
- [X] Check out handwritten samples for many of our APIs: https://github.com/GoogleCloudPlatform/nodejs-docs-samples

### A screenshot that you have tested with "Try this API".


N/A

### A step-by-step description of how to reproduce the issue, based on the linked reproduction.


Change MY_PROJECT to your project name, add credentials if needed and run.

### A clear and concise description of what the bug is, and what you expected to happen.

The application crashes with the following exception (which there is no way to catch). It should just emit error, and allow graceful handling.
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object
at _write (node:internal/streams/writable:474:13)
at Writable.write (node:internal/streams/writable:502:10)
at Duplexify._write (/project/node_modules/duplexify/index.js:212:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at Pumpify.<anonymous> (/project/node_modules/@google-cloud/speech/build/src/helpers.js:79:27)
at Object.onceWrapper (node:events:633:26)
at Pumpify.emit (node:events:518:28)
at obj.<computed> [as _write] (/project/node_modules/stubs/index.js:28:22)
at doWrite (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:390:139)
at writeOrBuffer (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:381:5)
at Writable.write (/project/node_modules/duplexify/node_modules/readable-stream/lib/_stream_writable.js:302:11)
at PassThrough.ondata (node:internal/streams/readable:1007:22)
at PassThrough.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:559:12) {
code: 'ERR_INVALID_ARG_TYPE'

### Link to the code that reproduces this issue. A link to a **public** Github Repository with a minimal reproduction.


https://gist.github.com/orgads/13cbf44c91923da27d8772b5f10489c9

### A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **

No library should crash an application this way.
17 changes: 17 additions & 0 deletions .github/scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "tests",
"private": true,
"description": "tests for script",
"scripts": {
"test": "mocha close-invalid-link.test.cjs && mocha close-or-remove-response-label.test.cjs"
},
"author": "Google Inc.",
"license": "Apache-2.0",
"engines": {
"node": ">=18"
},
"devDependencies": {
"@octokit/rest": "^21.0.2",
"mocha": "^11.0.1"
}
}
1 change: 1 addition & 0 deletions ci/run_conditional_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ fi
subdirs=(
containers
packages
scripts
)

RETVAL=0
Expand Down
1 change: 1 addition & 0 deletions ci/run_single_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ set -e

export REGION_ID='uc'
export PROJECT_ROOT=$(realpath $(dirname "${BASH_SOURCE[0]}")/..)
export NODE_OPTIONS=--max_old_space_size=4096

if [ -z "${BUILD_TYPE}" ]; then
echo "missing BUILD_TYPE env var"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ describe('v1alpha.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedResponse = generateSampleMessage(
new protos.google.ai.generativelanguage.v1alpha.CachedContent()
);
Expand Down Expand Up @@ -571,7 +571,7 @@ describe('v1alpha.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedResponse = generateSampleMessage(
new protos.google.ai.generativelanguage.v1alpha.CachedContent()
);
Expand Down Expand Up @@ -619,7 +619,7 @@ describe('v1alpha.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedError = new Error('expected');
client.innerApiCalls.updateCachedContent = stubSimpleCall(
undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ describe('v1beta.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedResponse = generateSampleMessage(
new protos.google.ai.generativelanguage.v1beta.CachedContent()
);
Expand Down Expand Up @@ -571,7 +571,7 @@ describe('v1beta.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedResponse = generateSampleMessage(
new protos.google.ai.generativelanguage.v1beta.CachedContent()
);
Expand Down Expand Up @@ -619,7 +619,7 @@ describe('v1beta.CacheServiceClient', () => {
['cachedContent', 'name']
);
request.cachedContent.name = defaultValue1;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1}`;
const expectedHeaderRequestParams = `cached_content.name=${defaultValue1 ?? ''}`;
const expectedError = new Error('expected');
client.innerApiCalls.updateCachedContent = stubSimpleCall(
undefined,
Expand Down
Loading

0 comments on commit ecc4989

Please sign in to comment.