aws / aws-toolkit-vscode

@@ -17,7 +17,6 @@
Loading
17 17
18 18
const LEGACY_SETTINGS_TELEMETRY_VALUE_DISABLE = 'Disable'
19 19
const LEGACY_SETTINGS_TELEMETRY_VALUE_ENABLE = 'Enable'
20 -
const TELEMETRY_SETTING_DEFAULT = true
21 20
22 21
export const noticeResponseViewSettings = localize('AWS.telemetry.notificationViewSettings', 'Settings')
23 22
export const noticeResponseOk = localize('AWS.telemetry.notificationOk', 'OK')
@@ -37,7 +36,13 @@
Loading
37 36
export async function activate(extensionContext: vscode.ExtensionContext, awsContext: AwsContext, settings: Settings) {
38 37
    globals.telemetry = new DefaultTelemetryService(extensionContext, awsContext, getComputeRegion())
39 38
40 -
    const config = new TelemetryConfig(settings)
39 +
    const config = new TelemetryConfig(
40 +
        settings,
41 +
        // Disable `throwInvalid` because:
42 +
        //   1. Telemetry must never prevent normal Toolkit operation.
43 +
        //   2. For tests, bad data is intentional, so these errors add unwanted noise in the test logs.
44 +
        false
45 +
    )
41 46
    globals.telemetry.telemetryEnabled = config.isEnabled()
42 47
43 48
    extensionContext.subscriptions.push(
@@ -50,7 +55,7 @@
Loading
50 55
51 56
    // Prompt user about telemetry if they haven't been
52 57
    if (!isCloud9() && !hasUserSeenTelemetryNotice(extensionContext)) {
53 -
        showTelemetryNotice(extensionContext, config)
58 +
        showTelemetryNotice(extensionContext)
54 59
    }
55 60
}
56 61
@@ -71,17 +76,7 @@
Loading
71 76
72 77
export class TelemetryConfig extends fromExtensionManifest('aws', { telemetry: convertLegacy }) {
73 78
    public isEnabled(): boolean {
74 -
        try {
75 -
            return this.get('telemetry', TELEMETRY_SETTING_DEFAULT)
76 -
        } catch (error) {
77 -
            vscode.window.showErrorMessage(
78 -
                localize(
79 -
                    'AWS.message.error.settings.telemetry.invalid_type',
80 -
                    'The aws.telemetry value must be a boolean'
81 -
                )
82 -
            )
83 -
            return TELEMETRY_SETTING_DEFAULT
84 -
        }
79 +
        return this.get('telemetry', true)
85 80
    }
86 81
}
87 82
@@ -101,7 +96,7 @@
Loading
101 96
 * Prompts user to Enable/Disable/Defer on Telemetry, then
102 97
 * handles the response appropriately.
103 98
 */
104 -
function showTelemetryNotice(extensionContext: vscode.ExtensionContext, config: TelemetryConfig) {
99 +
function showTelemetryNotice(extensionContext: vscode.ExtensionContext) {
105 100
    getLogger().verbose('Showing telemetry notice')
106 101
107 102
    const telemetryNoticeText: string = localize(

@@ -166,18 +166,26 @@
Loading
166 166
    type Inner = FromDescriptor<T>
167 167
168 168
    // Class names are not always stable, especially when bundling
169 -
    function makeLogger(name = 'Settings') {
169 +
    function makeLogger(name = 'Settings', loglevel: 'debug' | 'error') {
170 170
        const prefix = `${isNameMangled() ? 'Settings' : name} (${section})`
171 -
        return (message: string) => getLogger().debug(`${prefix}: ${message}`)
171 +
        return (message: string) =>
172 +
            loglevel === 'debug'
173 +
                ? getLogger().debug(`${prefix}: ${message}`)
174 +
                : getLogger().error(`${prefix}: ${message}`)
172 175
    }
173 176
174 177
    return class AnonymousSettings implements TypedSettings<Inner> {
175 178
        private readonly config = this.settings.getSection(section)
176 179
        private readonly disposables: vscode.Disposable[] = []
177 180
        // TODO(sijaden): add metadata prop to `Logger` so we don't need to make one-off log functions
178 -
        protected readonly log = makeLogger(Object.getPrototypeOf(this)?.constructor?.name)
181 +
        protected readonly log = makeLogger(Object.getPrototypeOf(this)?.constructor?.name, 'debug')
182 +
        protected readonly logErr = makeLogger(Object.getPrototypeOf(this)?.constructor?.name, 'error')
179 183
180 -
        public constructor(private readonly settings: ClassToInterfaceType<Settings> = Settings.instance) {}
184 +
        public constructor(
185 +
            private readonly settings: ClassToInterfaceType<Settings> = Settings.instance,
186 +
            /** Throw an exception if the user config is invalid or the caller type doesn't match the stored type. */
187 +
            private readonly throwInvalid: boolean = isAutomation()
188 +
        ) {}
181 189
182 190
        public get onDidChange() {
183 191
            return this.getChangedEmitter().event
@@ -186,14 +194,11 @@
Loading
186 194
        public get<K extends keyof Inner>(key: K & string, defaultValue?: Inner[K]) {
187 195
            try {
188 196
                return this.getOrThrow(key, defaultValue)
189 -
            } catch (error) {
190 -
                this.log(`failed to read key "${key}": ${error}`)
191 -
192 -
                if (isAutomation() || defaultValue === undefined) {
193 -
                    throw new Error(`Failed to read key "${key}": ${error}`)
197 +
            } catch (e) {
198 +
                if (this.throwInvalid || defaultValue === undefined) {
199 +
                    throw new Error(`Failed to read key "${key}": ${e}`)
194 200
                }
195 -
196 -
                this.log(`using default value for "${key}"`)
201 +
                this.logErr(`using default for key "${key}", read failed: ${(e as Error).message ?? '?'}`)
197 202
198 203
                return defaultValue
199 204
            }
@@ -255,8 +260,13 @@
Loading
255 260
256 261
                for (const key of props.filter(isDifferent)) {
257 262
                    this.log(`key "${key}" changed`)
258 -
                    store[key] = this.get(key)
259 -
                    emitter.fire({ key })
263 +
                    try {
264 +
                        store[key] = this.get(key)
265 +
                        emitter.fire({ key })
266 +
                    } catch {
267 +
                        // getChangedEmitter() can't provide a default value so
268 +
                        // we must silence errors here. Logging is done by this.get().
269 +
                    }
260 270
                }
261 271
            })
262 272
Files Coverage
src 68.70%
Project Totals (371 files) 68.70%
2431972877
macos-unittests
2431972877
macos-unittests
2431972877
windows-unittests
2431972877
macos-unittests
2431972877
windows-unittests
1
# To validate:
2
#   cat codecov.yml | curl --data-binary @- https://codecov.io/validate
3

4
codecov:
5
    notify:
6
        require_ci_to_pass: no
7

8
coverage:
9
    precision: 2
10
    round: down
11
    range: '70...100'
12

13
    status:
14
        project:
15
            default:
16
                threshold: 1
17
                informational: true
18
        patch: no
19
        changes: no
20

21
comment: off
22

23
github_checks:
24
    annotations: false
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading