1- import React from "dom-chef" ;
21import browser from "webextension-polyfill" ;
32import alpha from "color-alpha" ;
43import Drop from "tether-drop" ;
@@ -27,15 +26,14 @@ import {
2726import { colors } from "../common/constants" ;
2827import { createDropdown } from "./utils/dropdown" ;
2928import {
30- getMetadata ,
3129 getComponents ,
3230 getCommitReport ,
3331 getFlags ,
3432 getBranchReport ,
3533} from "../common/fetchers" ;
3634import { print } from "src/utils" ;
35+ import Sentry from "../../common/sentry" ;
3736import { isFileUrl } from "../common/utils" ;
38- import Sentry from '../../common/sentry' ;
3937
4038const globals : {
4139 coverageReport ?: FileCoverageReport ;
@@ -47,7 +45,7 @@ const globals: {
4745 prompt ?: HTMLElement ;
4846} = { } ;
4947
50- init ( )
48+ init ( ) ;
5149
5250function init ( ) : Promise < void > {
5351 // this event discovered by "reverse-engineering GitHub"
@@ -63,21 +61,60 @@ function init(): Promise<void> {
6361
6462async function main ( ) : Promise < void > {
6563 try {
66- if ( ! isFileUrl ( document . URL ) ) {
64+ const urlMetadata = getMetadataFromURL ( ) ;
65+ if ( ! urlMetadata ) {
6766 print ( "file not detected at current URL" ) ;
6867 return ;
6968 }
69+ globals . coverageButton = createCoverageButton ( ) ;
70+ process ( urlMetadata ) ;
71+ } catch ( e ) {
72+ Sentry . captureException ( e ) ;
73+ throw e ;
74+ }
75+ }
7076
71- let metadata : FileMetadata ;
72- metadata = await getMetadata ( document . URL ) ;
77+ function getMetadataFromURL ( ) : FileMetadata | null {
78+ const regexp =
79+ / \/ (?< owner > .+ ?) \/ (?< repo > .+ ?) \/ b l o b \/ (?< branch > .+ ?) \/ (?< path > .+ ?) $ / ;
80+ const matches = regexp . exec ( window . location . pathname ) ;
81+ const groups = matches ?. groups ;
82+ if ( ! groups ) {
83+ return null ;
84+ }
7385
74- globals . coverageButton = createCoverageButton ( ) ;
86+ const branch = groups . branch ;
87+ const commitMatch = branch . match ( / [ \d a - f ] + / ) ;
7588
76- process ( metadata )
77- } catch ( e ) {
78- Sentry . captureException ( e )
79- throw e
89+ // branch could be a commit sha
90+ if (
91+ commitMatch &&
92+ commitMatch [ 0 ] . length == branch . length &&
93+ ( groups . branch . length === 40 || branch . length === 7 )
94+ ) {
95+ // branch is actually a commit sha
96+ let commit = branch ;
97+
98+ // if it's a short sha, we need to get the full sha
99+ if ( commit . length === 7 ) {
100+ const commitLink = document . querySelector (
101+ `[href^="/${ groups . owner } /${ groups . repo } /tree/${ commit } "]`
102+ ) ;
103+ if ( ! commitLink )
104+ throw new Error ( "Could not find commit link from short sha" ) ;
105+ const longSha = commitLink
106+ . getAttribute ( "href" )
107+ ?. match ( / [ \d a - f ] { 40 } / ) ?. [ 0 ] ;
108+ if ( ! longSha ) throw new Error ( "Could not get long sha from commit link" ) ;
109+ commit = longSha ;
110+ }
111+
112+ return {
113+ ...groups ,
114+ commit,
115+ } ;
80116 }
117+ return groups ;
81118}
82119
83120async function process ( metadata : FileMetadata ) : Promise < void > {
@@ -111,17 +148,16 @@ async function process(metadata: FileMetadata): Promise<void> {
111148 previousElement : globals . coverageButton ! ,
112149 selectedOptions : selectedFlags ,
113150 onClick : handleFlagClick ,
114- } )
115- . then ( ( { button, list } ) => {
116- globals . flagsButton = button ;
117- globals . flagsDrop = new Drop ( {
118- target : button ,
119- content : list ,
120- classes : "drop-theme-arrows codecov-z1 codecov-bg-white" ,
121- position : "bottom right" ,
122- openOn : "click" ,
123- } ) ;
124- } )
151+ } ) . then ( ( { button, list } ) => {
152+ globals . flagsButton = button ;
153+ globals . flagsDrop = new Drop ( {
154+ target : button ,
155+ content : list ,
156+ classes : "drop-theme-arrows codecov-z1 codecov-bg-white" ,
157+ position : "bottom right" ,
158+ openOn : "click" ,
159+ } ) ;
160+ } ) ;
125161 }
126162
127163 const components = await getComponents ( metadata ) ;
@@ -134,7 +170,7 @@ async function process(metadata: FileMetadata): Promise<void> {
134170 return [ ] ;
135171 } ) ;
136172
137- // TODO: allow setting selected flags for different files at the same time
173+ // TODO: allow setting selected components for different files at the same time
138174 if (
139175 selectedComponents . length > 0 &&
140176 _ . intersection ( components , selectedComponents ) . length === 0
@@ -151,35 +187,45 @@ async function process(metadata: FileMetadata): Promise<void> {
151187 previousElement : globals . coverageButton ! ,
152188 onClick : handleComponentClick ,
153189 selectedOptions : selectedComponents ,
154- } )
155- . then ( ( { button, list } ) => {
156- globals . componentsButton = button ;
157- globals . componentsDrop = new Drop ( {
158- target : button ,
159- content : list ,
160- classes : "drop-theme-arrows codecov-z1 codecov-bg-white" ,
161- position : "bottom right" ,
162- openOn : "click" ,
163- } ) ;
164- } )
190+ } ) . then ( ( { button, list } ) => {
191+ globals . componentsButton = button ;
192+ globals . componentsDrop = new Drop ( {
193+ target : button ,
194+ content : list ,
195+ classes : "drop-theme-arrows codecov-z1 codecov-bg-white" ,
196+ position : "bottom right" ,
197+ openOn : "click" ,
198+ } ) ;
199+ } ) ;
165200 }
166201
202+ // If commit sha is defined use that, otherwise just branch name
203+ const getReportFn = metadata . commit ? getCommitReport : getBranchReport ;
204+
167205 let coverageReportResponses : Array < FileCoverageReportResponse > ;
168206 try {
169- if ( selectedFlags ?. length > 0 ) {
207+ if ( selectedFlags ?. length > 0 && selectedComponents ?. length > 0 ) {
208+ coverageReportResponses = await Promise . all (
209+ selectedFlags . flatMap ( ( flag ) =>
210+ selectedComponents . map ( ( component ) =>
211+ getReportFn ( metadata , flag , component )
212+ )
213+ )
214+ ) ;
215+ } else if ( selectedFlags ?. length > 0 ) {
170216 coverageReportResponses = await Promise . all (
171- selectedFlags . map ( ( flag ) => getCommitReport ( metadata , flag , undefined ) )
217+ selectedFlags . map ( ( flag ) => getReportFn ( metadata , flag , undefined ) )
172218 ) ;
173219 } else if ( selectedComponents ?. length > 0 ) {
174220 coverageReportResponses = await Promise . all (
175221 selectedComponents . map ( ( component ) =>
176- getCommitReport ( metadata , undefined , component )
222+ getReportFn ( metadata , undefined , component )
177223 )
178224 ) ;
179225 } else {
180- coverageReportResponses = await Promise . all ( [
181- await getCommitReport ( metadata , undefined , undefined ) ,
182- ] ) ;
226+ coverageReportResponses = [
227+ await getReportFn ( metadata , undefined , undefined ) ,
228+ ] ;
183229 }
184230 } catch ( e ) {
185231 updateButton ( `Coverage: ⚠` ) ;
@@ -220,7 +266,6 @@ async function process(metadata: FileMetadata): Promise<void> {
220266 if ( _ . isEmpty ( coverageReport ) ) {
221267 updateButton ( `Coverage: N/A` ) ;
222268 globals . coverageReport = { } ;
223- await promptPastReport ( metadata ) ;
224269 return ;
225270 }
226271
@@ -232,40 +277,6 @@ async function process(metadata: FileMetadata): Promise<void> {
232277 animateAndAnnotateLines ( noVirtLineSelector , annotateLine ) ;
233278}
234279
235- async function promptPastReport ( metadata : FileMetadata ) : Promise < void > {
236- if ( ! metadata . branch ) {
237- return ;
238- }
239- const response = await getBranchReport ( metadata ) ;
240- const regexp = / a p p .c o d e c o v .i o \/ g i t h u b \/ .* \/ .* \/ c o m m i t \/ (?< commit > .* ) \/ b l o b / ;
241- const matches = regexp . exec ( response . commit_file_url ) ;
242- const commit = matches ?. groups ?. commit ;
243- if ( ! commit ) {
244- throw new Error ( "Could not parse commit hash from response for past coverage report" )
245- }
246- const link = document . URL . replace (
247- `blob/${ metadata . branch } ` ,
248- `blob/${ commit } `
249- ) ;
250- globals . prompt = createPrompt (
251- < span >
252- Coverage report not available for branch HEAD (
253- { metadata . commit . substr ( 0 , 7 ) } ), most recent coverage report for this
254- branch available at commit < a href = { link } > { commit . substr ( 0 , 7 ) } </ a >
255- </ span >
256- ) ;
257- }
258-
259- function createPrompt ( child : any ) {
260- const ref = document . querySelector ( '[data-testid="latest-commit"]' )
261- ?. parentElement ?. parentElement ;
262- if ( ! ref ) {
263- throw new Error ( "Could not find reference element to render prompt" )
264- }
265- const prompt = < div className = "codecov-mb2 codecov-mx1" > { child } </ div > ;
266- return ref . insertAdjacentElement ( "afterend" , prompt ) as HTMLElement ;
267- }
268-
269280function createCoverageButton ( ) {
270281 const rawButton = document . querySelector ( '[data-testid="raw-button"]' ) ;
271282 if ( ! rawButton ) {
0 commit comments