Skip to content

Commit 174148b

Browse files
committed
Merge branch 'master' of github.com:leigaol/aws-toolkit-vscode into internal_falcon_release
2 parents e2354da + 35502be commit 174148b

File tree

39 files changed

+564
-195
lines changed

39 files changed

+564
-195
lines changed

.github/workflows/filterDuplicates.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ async function run() {
111111
console.log('%s duplicates found', filteredDuplicates.length)
112112
if (filteredDuplicates.length > 0) {
113113
console.log(formatDuplicates(filteredDuplicates, commitHash, repoName))
114-
console.log(
115-
'* Hint: if these duplicates appear unrelated to the changes, rebase onto the latest target branch.'
116-
)
117114
process.exit(1)
118115
}
119116
}

.github/workflows/node.js.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ jobs:
8484
git remote add forkUpstream https://github.com/$REPO_NAME # URL of the fork
8585
git fetch forkUpstream # Fetch fork
8686
87+
- name: Merge in target branch to avoid false negatives.
88+
env:
89+
TARGET_BRANCH: ${{ github.event.pull_request.base.ref }}
90+
# Note: "git merge" should always succeed here, because GHA won't
91+
# start the job if there are merge conflicts. https://github.com/orgs/community/discussions/11265
92+
# Also, because `git merge` makes a commit, we need to establish an identity to avoid 'Committer identity unknown' error
93+
run: |
94+
git config --global user.name "aws-toolkit-automation"
95+
git config --global user.email "<>"
96+
git merge origin/$TARGET_BRANCH
97+
8798
- name: Compute git diff
8899
env:
89100
CURRENT_BRANCH: ${{ github.head_ref }}

buildspec/release/80notify.yml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ phases:
1414
build:
1515
commands:
1616
- echo "TARGET_EXTENSION=${TARGET_EXTENSION}"
17-
- EXTENSION_NAME=$([ "$TARGET_EXTENSION" = "amazonq" ] && echo "Amazon Q" || echo "AWS Toolkit")
18-
- VERSION=$(node -e "console.log(require('./packages/${TARGET_EXTENSION}/package.json').version);")
19-
- CHANGELOG=$(cat packages/${TARGET_EXTENSION}/CHANGELOG.md | perl -ne 'BEGIN{$/="\n\n"} print if $. == 2')
20-
- MESSAGE=$(envsubst < "$GITHUB_WORKSPACE/buildspec/release/notify.txt")
21-
- DATA="{'Content':'${MESSAGE}'}"
17+
- export EXTENSION_NAME=$([ "$TARGET_EXTENSION" = "amazonq" ] && echo "Amazon Q" || echo "AWS Toolkit")
18+
- export VERSION=$(node -e "console.log(require('./packages/${TARGET_EXTENSION}/package.json').version);")
19+
- export CHANGELOG=$(cat packages/${TARGET_EXTENSION}/CHANGELOG.md | perl -ne 'BEGIN{$/="\n\n"} print if $. == 2')
20+
- MESSAGE=$(envsubst < ./buildspec/release/notify.txt)
2221
- |
23-
# TODO: Enable for prod only after testing
24-
if [ "$STAGE" = "prod" ]; then
25-
echo "SKIPPED (stage=${STAGE}): 'curl -v POST \"[SLACK_URL]\" -H \"Content-Type:application/json\" --data $DATA'"
22+
if [ "$STAGE" != "prod" ]; then
23+
echo "SKIPPED (stage=${STAGE}): 'curl -v POST \"[NOTIFY_URL]\" -H \"Content-Type:application/json\" --data \"{\"Content\":\"${MESSAGE}\"}\"'"
2624
exit 0
2725
fi
28-
curl -v POST "${NOTIFY_URL}" -H "Content-Type:application/json" --data $DATA
26+
curl -v POST "${NOTIFY_URL}" -H "Content-Type:application/json" --data "{\"Content\":\"${MESSAGE}\"}"

buildspec/release/notify.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
Released ${EXTENSION_NAME} v${VERSION} for VSCode
1+
Released ${EXTENSION_NAME} v${VERSION} for VS Code
22

33
${CHANGELOG}
44

55
Changelog: https://github.com/aws/aws-toolkit-vscode/blob/master/packages/${TARGET_EXTENSION}/CHANGELOG.md
6-
Release Arifact: https://github.com/aws/aws-toolkit-vscode/releases/tag/${TARGET_EXTENSION}/v${VERSION}
6+
Release Artifact: https://github.com/aws/aws-toolkit-vscode/releases/tag/${TARGET_EXTENSION}/v${VERSION}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "/review: Auto-review should not remove issues from manual reviews"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q /doc: Add support for infrastructure diagrams"
4+
}

packages/amazonq/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
142142
// Give time for the extension to finish initializing.
143143
globals.clock.setTimeout(async () => {
144144
CommonAuthWebview.authSource = ExtStartUpSources.firstStartUp
145-
void focusAmazonQPanel.execute(placeholder, 'firstStartUp')
145+
void focusAmazonQPanel.execute(placeholder, ExtStartUpSources.firstStartUp)
146146
}, 1000)
147147
}
148148
}

packages/amazonq/test/unit/amazonqFeatureDev/util/files.test.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as vscode from 'vscode'
66
import assert from 'assert'
77
import {
88
prepareRepoData,
9+
PrepareRepoDataOptions,
910
TelemetryHelper,
1011
ContentLengthError,
1112
maxRepoSizeBytes,
@@ -46,23 +47,23 @@ const testDevfilePrepareRepo = async (devfileEnabled: boolean) => {
4647
.stub(CodeWhispererSettings.instance, 'getAutoBuildSetting')
4748
.returns(devfileEnabled ? { [workspace.uri.fsPath]: true } : {})
4849

49-
await testPrepareRepoData([workspace], expectedFiles)
50+
await testPrepareRepoData([workspace], expectedFiles, { telemetry: new TelemetryHelper() })
5051
}
5152

5253
const testPrepareRepoData = async (
5354
workspaces: vscode.WorkspaceFolder[],
5455
expectedFiles: string[],
56+
prepareRepoDataOptions: PrepareRepoDataOptions,
5557
expectedTelemetryMetrics?: Array<{ metricName: MetricName; value: any }>
5658
) => {
5759
expectedFiles.sort((a, b) => a.localeCompare(b))
58-
const telemetry = new TelemetryHelper()
5960
const result = await prepareRepoData(
6061
workspaces.map((ws) => ws.uri.fsPath),
6162
workspaces as CurrentWsFolders,
62-
telemetry,
6363
{
6464
record: () => {},
65-
} as unknown as Span<AmazonqCreateUpload>
65+
} as unknown as Span<AmazonqCreateUpload>,
66+
prepareRepoDataOptions
6667
)
6768

6869
assert.strictEqual(Buffer.isBuffer(result.zipFileBuffer), true)
@@ -84,6 +85,8 @@ const testPrepareRepoData = async (
8485

8586
describe('file utils', () => {
8687
describe('prepareRepoData', function () {
88+
const defaultPrepareRepoDataOptions: PrepareRepoDataOptions = { telemetry: new TelemetryHelper() }
89+
8790
afterEach(() => {
8891
sinon.restore()
8992
})
@@ -92,21 +95,33 @@ describe('file utils', () => {
9295
const folder = await TestFolder.create()
9396
await folder.write('file1.md', 'test content')
9497
await folder.write('file2.md', 'test content')
98+
await folder.write('docs/infra.svg', 'test content')
9599
const workspace = getWorkspaceFolder(folder.path)
96100

97-
await testPrepareRepoData([workspace], ['file1.md', 'file2.md'])
101+
await testPrepareRepoData([workspace], ['file1.md', 'file2.md'], defaultPrepareRepoDataOptions)
102+
})
103+
104+
it('infrastructure diagram is included', async function () {
105+
const folder = await TestFolder.create()
106+
await folder.write('file1.md', 'test content')
107+
await folder.write('file2.svg', 'test content')
108+
await folder.write('docs/infra.svg', 'test content')
109+
const workspace = getWorkspaceFolder(folder.path)
110+
111+
await testPrepareRepoData([workspace], ['file1.md', 'docs/infra.svg'], {
112+
telemetry: new TelemetryHelper(),
113+
isIncludeInfraDiagram: true,
114+
})
98115
})
99116

100117
it('prepareRepoData ignores denied file extensions', async function () {
101118
const folder = await TestFolder.create()
102119
await folder.write('file.mp4', 'test content')
103120
const workspace = getWorkspaceFolder(folder.path)
104121

105-
await testPrepareRepoData(
106-
[workspace],
107-
[],
108-
[{ metricName: 'amazonq_bundleExtensionIgnored', value: { filenameExt: 'mp4', count: 1 } }]
109-
)
122+
await testPrepareRepoData([workspace], [], defaultPrepareRepoDataOptions, [
123+
{ metricName: 'amazonq_bundleExtensionIgnored', value: { filenameExt: 'mp4', count: 1 } },
124+
])
110125
})
111126

112127
it('should ignore devfile.yaml when setting is disabled', async function () {
@@ -122,14 +137,18 @@ describe('file utils', () => {
122137
const folder = await TestFolder.create()
123138
await folder.write('file.md', 'test content')
124139
const workspace = getWorkspaceFolder(folder.path)
125-
const telemetry = new TelemetryHelper()
126140

127141
sinon.stub(fs, 'stat').resolves({ size: 2 * maxRepoSizeBytes } as vscode.FileStat)
128142
await assert.rejects(
129143
() =>
130-
prepareRepoData([workspace.uri.fsPath], [workspace], telemetry, {
131-
record: () => {},
132-
} as unknown as Span<AmazonqCreateUpload>),
144+
prepareRepoData(
145+
[workspace.uri.fsPath],
146+
[workspace],
147+
{
148+
record: () => {},
149+
} as unknown as Span<AmazonqCreateUpload>,
150+
defaultPrepareRepoDataOptions
151+
),
133152
ContentLengthError
134153
)
135154
})
@@ -144,7 +163,11 @@ describe('file utils', () => {
144163
const workspace2 = getWorkspaceFolder(folder.path + '/innerFolder')
145164
const folderName = path.basename(folder.path)
146165

147-
await testPrepareRepoData([workspace1, workspace2], [`${folderName}_${workspace1.name}/${testFilePath}`])
166+
await testPrepareRepoData(
167+
[workspace1, workspace2],
168+
[`${folderName}_${workspace1.name}/${testFilePath}`],
169+
defaultPrepareRepoDataOptions
170+
)
148171
})
149172
})
150173
})

packages/core/src/amazonq/session/sessionState.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as vscode from 'vscode'
77
import { ToolkitError } from '../../shared/errors'
88
import globals from '../../shared/extensionGlobals'
99
import { getLogger } from '../../shared/logger/logger'
10-
import { telemetry } from '../../shared/telemetry/telemetry'
10+
import { AmazonqCreateUpload, Span, telemetry } from '../../shared/telemetry/telemetry'
1111
import { VirtualFileSystem } from '../../shared/virtualFilesystem'
1212
import { CodeReference, UploadHistory } from '../webview/ui/connector'
1313
import { AuthUtil } from '../../codewhisperer/util/authUtil'
@@ -25,7 +25,7 @@ import {
2525
SessionStateInteraction,
2626
SessionStatePhase,
2727
} from '../commons/types'
28-
import { prepareRepoData, getDeletedFileInfos, registerNewFiles } from '../util/files'
28+
import { prepareRepoData, getDeletedFileInfos, registerNewFiles, PrepareRepoDataOptions } from '../util/files'
2929
import { uploadCode } from '../util/upload'
3030

3131
export const EmptyCodeGenID = 'EMPTY_CURRENT_CODE_GENERATION_ID'
@@ -227,11 +227,11 @@ export abstract class BasePrepareCodeGenState implements SessionState {
227227
amazonqConversationId: this.config.conversationId,
228228
credentialStartUrl: AuthUtil.instance.startUrl,
229229
})
230-
const { zipFileBuffer, zipFileChecksum } = await prepareRepoData(
230+
const { zipFileBuffer, zipFileChecksum } = await this.prepareProjectZip(
231231
this.config.workspaceRoots,
232232
this.config.workspaceFolders,
233-
action.telemetry,
234-
span
233+
span,
234+
{ telemetry: action.telemetry }
235235
)
236236
const uploadId = randomUUID()
237237
const { uploadUrl, kmsKeyArn } = await this.config.proxyClient.createUploadUrl(
@@ -251,6 +251,15 @@ export abstract class BasePrepareCodeGenState implements SessionState {
251251
const nextState = this.createNextState({ ...this.config, uploadId })
252252
return nextState.interact(action)
253253
}
254+
255+
protected async prepareProjectZip(
256+
workspaceRoots: string[],
257+
workspaceFolders: CurrentWsFolders,
258+
span: Span<AmazonqCreateUpload>,
259+
options: PrepareRepoDataOptions
260+
) {
261+
return await prepareRepoData(workspaceRoots, workspaceFolders, span, options)
262+
}
254263
}
255264

256265
export interface CodeGenerationParams {

packages/core/src/amazonq/util/files.ts

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66
import * as vscode from 'vscode'
77
import * as path from 'path'
8-
import { collectFiles, getWorkspaceFoldersByPrefixes } from '../../shared/utilities/workspaceUtils'
8+
import {
9+
collectFiles,
10+
CollectFilesFilter,
11+
defaultExcludePatterns,
12+
getWorkspaceFoldersByPrefixes,
13+
} from '../../shared/utilities/workspaceUtils'
914

1015
import { ContentLengthError, PrepareRepoFailedError } from '../../amazonqFeatureDev/errors'
1116
import { getLogger } from '../../shared/logger/logger'
@@ -24,27 +29,69 @@ import { isPresent } from '../../shared/utilities/collectionUtils'
2429
import { AuthUtil } from '../../codewhisperer/util/authUtil'
2530
import { TelemetryHelper } from '../util/telemetryHelper'
2631

32+
export const SvgFileExtension = '.svg'
33+
2734
export async function checkForDevFile(root: string) {
2835
const devFilePath = root + '/devfile.yaml'
2936
const hasDevFile = await fs.existsFile(devFilePath)
3037
return hasDevFile
3138
}
3239

40+
function isInfraDiagramFile(relativePath: string) {
41+
return (
42+
relativePath.toLowerCase().endsWith(path.join('docs', 'infra.dot')) ||
43+
relativePath.toLowerCase().endsWith(path.join('docs', 'infra.svg'))
44+
)
45+
}
46+
47+
export type PrepareRepoDataOptions = {
48+
telemetry?: TelemetryHelper
49+
zip?: ZipStream
50+
isIncludeInfraDiagram?: boolean
51+
}
52+
3353
/**
3454
* given the root path of the repo it zips its files in memory and generates a checksum for it.
3555
*/
3656
export async function prepareRepoData(
3757
repoRootPaths: string[],
3858
workspaceFolders: CurrentWsFolders,
39-
telemetry: TelemetryHelper,
4059
span: Span<AmazonqCreateUpload>,
41-
zip: ZipStream = new ZipStream()
60+
options?: PrepareRepoDataOptions
4261
) {
4362
try {
63+
const telemetry = options?.telemetry
64+
const isIncludeInfraDiagram = options?.isIncludeInfraDiagram ?? false
65+
const zip = options?.zip ?? new ZipStream()
66+
4467
const autoBuildSetting = CodeWhispererSettings.instance.getAutoBuildSetting()
4568
const useAutoBuildFeature = autoBuildSetting[repoRootPaths[0]] ?? false
69+
const excludePatterns: string[] = []
70+
let filterFn: CollectFilesFilter | undefined = undefined
71+
4672
// We only respect gitignore file rules if useAutoBuildFeature is on, this is to avoid dropping necessary files for building the code (e.g. png files imported in js code)
47-
const files = await collectFiles(repoRootPaths, workspaceFolders, true, maxRepoSizeBytes, !useAutoBuildFeature)
73+
if (!useAutoBuildFeature) {
74+
if (isIncludeInfraDiagram) {
75+
// ensure svg is not filtered out by files search
76+
excludePatterns.push(...defaultExcludePatterns.filter((p) => !p.endsWith(SvgFileExtension)))
77+
// ensure only infra diagram is included from all svg files
78+
filterFn = (relativePath: string) => {
79+
if (!relativePath.toLowerCase().endsWith(SvgFileExtension)) {
80+
return false
81+
}
82+
return !isInfraDiagramFile(relativePath)
83+
}
84+
} else {
85+
excludePatterns.push(...defaultExcludePatterns)
86+
}
87+
}
88+
89+
const files = await collectFiles(repoRootPaths, workspaceFolders, {
90+
maxSizeBytes: maxRepoSizeBytes,
91+
excludeByGitIgnore: true,
92+
excludePatterns: excludePatterns,
93+
filterFn: filterFn,
94+
})
4895

4996
let totalBytes = 0
5097
const ignoredExtensionMap = new Map<string, number>()
@@ -68,9 +115,15 @@ export async function prepareRepoData(
68115
}
69116
const isCodeFile_ = isCodeFile(file.relativeFilePath)
70117
const isDevFile = file.relativeFilePath === 'devfile.yaml'
71-
// When useAutoBuildFeature is on, only respect the gitignore rules filtered earlier and apply the size limit, otherwise, exclude all non code files and gitignore files
72-
const isNonCodeFileAndIgnored = useAutoBuildFeature ? false : !isCodeFile_ || isDevFile
73-
if (fileSize >= maxFileSizeBytes || isNonCodeFileAndIgnored) {
118+
const isInfraDiagramFileExt = isInfraDiagramFile(file.relativeFilePath)
119+
120+
let isExcludeFile = fileSize >= maxFileSizeBytes
121+
// When useAutoBuildFeature is on, only respect the gitignore rules filtered earlier and apply the size limit
122+
if (!isExcludeFile && !useAutoBuildFeature) {
123+
isExcludeFile = isDevFile || (!isCodeFile_ && (!isIncludeInfraDiagram || !isInfraDiagramFileExt))
124+
}
125+
126+
if (isExcludeFile) {
74127
if (!isCodeFile_) {
75128
const re = /(?:\.([^.]+))?$/
76129
const extensionArray = re.exec(file.relativeFilePath)
@@ -83,6 +136,7 @@ export async function prepareRepoData(
83136
}
84137
continue
85138
}
139+
86140
totalBytes += fileSize
87141
// Paths in zip should be POSIX compliant regardless of OS
88142
// Reference: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
@@ -117,7 +171,10 @@ export async function prepareRepoData(
117171
}
118172
}
119173

120-
telemetry.setRepositorySize(totalBytes)
174+
if (telemetry) {
175+
telemetry.setRepositorySize(totalBytes)
176+
}
177+
121178
span.record({ amazonqRepositorySize: totalBytes })
122179
const zipResult = await zip.finalize()
123180

0 commit comments

Comments
 (0)