2024-08-21 01:55:45 -06:00
const FIELD _MAPPINGS = {
Platform : 'What platforms are you having the problem on?' ,
Version : 'Version' ,
SystemVersion : 'System Version' ,
DeviceType : 'On what device are you experiencing the issue?' ,
Architecture : 'Architecture' ,
Description : 'What happened?' ,
ReproductionLink : 'Reproduction Link' ,
Reproduction : 'Reproduction' ,
} ;
const PLATFORM _LABELS = {
iOS : 'Platform: iOS' ,
visionOS : 'Platform: iOS' ,
'Apple tvOS' : 'Platform: iOS' ,
Android : 'Platform: Android' ,
'Android TV' : 'Platform: Android' ,
Windows : 'Platform: Windows' ,
web : 'Platform: Web' ,
} ;
const BOT _LABELS = [
'Missing Info' ,
'Repro Provided' ,
'Missing Repro' ,
'Waiting for Review' ,
'Newer Version Available' ,
... Object . values ( PLATFORM _LABELS ) ,
] ;
2024-09-28 06:52:23 -06:00
const SKIP _LABEL = 'No Validation' ;
2024-08-23 02:53:51 -06:00
2024-08-21 01:55:45 -06:00
const MESSAGE = {
2024-12-23 08:28:25 -07:00
FEATURE _REQUEST : ` Thanks for the feature request! Check out our roadmap [here](https://github.com/TheWidlarzGroup/react-native-video/discussions/3351). If your request is already there – great! If not, give us some time, and we'll get back to you with information on when TheWidlarzGroup can address it as part of our free open-source support. Alternatively, [contact us](https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=feature-request#Contact) to discuss ways to speed up the process. ` ,
2024-08-21 01:55:45 -06:00
BUG _REPORT : ` Thank you for your bug report. We will review it and get back to you if we need more information. ` ,
MISSING _INFO : ( missingFields ) => {
return ` Thank you for your issue report. Please note that the following information is missing or incomplete: \n \n ${ missingFields
. map ( ( field ) => ` - ${ field . replace ( 'missing-' , '' ) } ` )
. join (
'\n' ,
) } \ n \ nPlease update your issue with this information to help us address it more effectively .
\ n > Note : issues without complete information have a lower priority ` ;
} ,
OUTDATED _VERSION : ( issueVersion , latestVersion ) => {
return (
2024-08-26 09:25:15 -06:00
` There is a newer version of the library available. ` +
` You are using version ${ issueVersion } , while the latest stable version is ${ latestVersion } . ` +
2024-08-21 01:55:45 -06:00
` Please update to the latest version and check if the issue still exists. ` +
` \n > Note: If the issue still exists, please update the issue report with the latest information. `
) ;
} ,
} ;
const checkLatestVersion = async ( ) => {
try {
const response = await fetch (
'https://registry.npmjs.org/react-native-video/latest' ,
) ;
const data = await response . json ( ) ;
return data . version ;
} catch ( error ) {
console . error ( 'Error checking latest version:' , error ) ;
return null ;
}
} ;
const getFieldValue = ( body , field ) => {
if ( ! FIELD _MAPPINGS [ field ] ) {
console . warn ( 'Field not supported:' , field ) ;
return '' ;
}
const fieldValue = FIELD _MAPPINGS [ field ] ;
const sections = body . split ( '###' ) ;
const section = sections . find ( ( section ) => {
// Find the section that contains the field
// For Reproduction, we need to make sure that we don't match Reproduction Link
if ( field === 'Reproduction' ) {
return (
section . includes ( fieldValue ) && ! section . includes ( 'Reproduction Link' )
) ;
}
return section . includes ( fieldValue ) ;
} ) ;
return section ? section . replace ( fieldValue , '' ) . trim ( ) : '' ;
} ;
const validateBugReport = async ( body , labels ) => {
const selectedPlatforms = getFieldValue ( body , 'Platform' )
. split ( ',' )
. map ( ( p ) => p . trim ( ) ) ;
if ( selectedPlatforms . length === 0 ) {
labels . add ( 'missing-platform' ) ;
} else {
selectedPlatforms . forEach ( ( platform ) => {
const label = PLATFORM _LABELS [ platform ] ;
if ( label ) {
labels . add ( label ) ;
} else {
console . warn ( 'Platform not supported' , platform ) ;
}
} ) ;
}
const version = getFieldValue ( body , 'Version' ) ;
if ( version ) {
const words = version . split ( ' ' ) ;
const versionPattern = /\d+\.\d+\.\d+/ ;
const isVersionValid = words . some ( ( word ) => versionPattern . test ( word ) ) ;
if ( ! isVersionValid ) {
labels . add ( 'missing-version' ) ;
}
const latestVersion = await checkLatestVersion ( ) ;
if ( latestVersion && latestVersion !== version ) {
labels . add ( ` outdated-version- ${ version } - ${ latestVersion } ` ) ;
}
}
const fields = [
{
name : 'SystemVersion' ,
invalidValue :
'What version of the system is using device that you are experiencing the issue?' ,
} ,
{ name : 'DeviceType' } ,
{ name : 'Architecture' } ,
{ name : 'Description' , invalidValue : 'A bug happened!' } ,
{ name : 'Reproduction' , invalidValue : 'Step to reproduce this bug are:' } ,
{ name : 'ReproductionLink' , invalidValue : 'repository link' } ,
] ;
fields . forEach ( ( { name , invalidValue } ) => {
const value = getFieldValue ( body , name ) ;
if ( ! value || value === invalidValue ) {
const fieldName = FIELD _MAPPINGS [ name ] ;
labels . add ( ` missing- ${ fieldName . toLowerCase ( ) } ` ) ;
}
} ) ;
} ;
const validateFeatureRequest = ( body , labels ) => {
// Implement feature request validation logic here
} ;
const handleIssue = async ( { github , context } ) => {
const { issue } = context . payload ;
const { body } = issue ;
const labels = new Set ( issue . labels . map ( ( label ) => label . name ) ) ;
2024-09-28 06:52:23 -06:00
if ( labels . has ( SKIP _LABEL ) ) {
console . log ( 'Skiping Issue Validation' ) ;
2024-08-23 02:53:51 -06:00
return ;
}
2024-08-21 01:55:45 -06:00
// Clear out labels that are added by the bot
BOT _LABELS . forEach ( ( label ) => labels . delete ( label ) ) ;
const isBug = labels . has ( 'bug' ) ;
const isFeature = labels . has ( 'feature' ) ;
if ( isFeature ) {
await handleFeatureRequest ( { github , context , body , labels } ) ;
} else if ( isBug ) {
await handleBugReport ( { github , context , body , labels } ) ;
} else {
console . warn ( 'Issue is not a bug or feature request' ) ;
}
await updateIssueLabels ( { github , context , labels } ) ;
} ;
const handleFeatureRequest = async ( { github , context , body , labels } ) => {
validateFeatureRequest ( body , labels ) ;
const comment = MESSAGE . FEATURE _REQUEST ;
await createComment ( { github , context , body : comment } ) ;
} ;
const handleBugReport = async ( { github , context , body , labels } ) => {
await validateBugReport ( body , labels ) ;
if ( Array . from ( labels ) . some ( ( label ) => label . startsWith ( 'missing-' ) ) ) {
await handleMissingInformation ( { github , context , labels } ) ;
} else {
await handleValidReport ( { github , context , labels } ) ;
}
} ;
const handleMissingInformation = async ( { github , context , labels } ) => {
const missingFields = Array . from ( labels ) . filter ( ( label ) =>
label . startsWith ( 'missing-' ) ,
) ;
2024-08-22 03:22:11 -06:00
const outdatedVersionLabel = Array . from ( labels ) . find ( ( label ) =>
2024-08-21 01:55:45 -06:00
label . startsWith ( 'outdated-version' ) ,
) ;
if ( missingFields . length > 0 ) {
let comment = MESSAGE . MISSING _INFO ( missingFields ) ;
if ( outdatedVersionLabel ) {
const [ , , issueVersion , latestVersion ] = outdatedVersionLabel . split ( '-' ) ;
comment += ` \n \n ${ MESSAGE . OUTDATED _VERSION (
issueVersion ,
latestVersion ,
) } ` ;
}
2024-09-28 06:52:23 -06:00
await hidePreviousComments ( { github , context } ) ;
2024-08-21 01:55:45 -06:00
await createComment ( { github , context , body : comment } ) ;
}
updateLabelsForMissingInfo ( labels ) ;
} ;
const handleValidReport = async ( { github , context , labels } ) => {
let comment = MESSAGE . BUG _REPORT ;
const outdatedVersionLabel = Array . from ( labels ) . find ( ( label ) =>
label . startsWith ( 'outdated-version' ) ,
) ;
if ( outdatedVersionLabel ) {
const [ , , issueVersion , latestVersion ] = outdatedVersionLabel . split ( '-' ) ;
comment += ` \n \n ${ MESSAGE . OUTDATED _VERSION ( issueVersion , latestVersion ) } ` ;
labels . add ( 'Newer Version Available' ) ;
}
2024-09-28 06:52:23 -06:00
await hidePreviousComments ( { github , context } ) ;
2024-08-21 01:55:45 -06:00
await createComment ( { github , context , body : comment } ) ;
labels . add ( 'Repro Provided' ) ;
labels . add ( 'Waiting for Review' ) ;
} ;
const createComment = async ( { github , context , body } ) => {
await github . rest . issues . createComment ( {
owner : context . repo . owner ,
repo : context . repo . repo ,
issue _number : context . payload . issue . number ,
body ,
} ) ;
} ;
const updateIssueLabels = async ( { github , context , labels } ) => {
const labelsToAdd = Array . from ( labels ) . filter (
( label ) => ! label . startsWith ( 'missing-' ) && ! label . startsWith ( 'outdated-' ) ,
) ;
await github . rest . issues . update ( {
owner : context . repo . owner ,
repo : context . repo . repo ,
issue _number : context . payload . issue . number ,
labels : labelsToAdd ,
} ) ;
} ;
2024-09-28 06:52:23 -06:00
const hidePreviousComments = async ( { github , context } ) => {
const comments = await github . rest . issues . listComments ( {
owner : context . repo . owner ,
repo : context . repo . repo ,
issue _number : context . payload . issue . number ,
} ) ;
2025-01-10 04:01:31 -07:00
// Filter for bot comments that aren't already hidden
const unhiddenBotComments = comments . data . filter (
( comment ) =>
comment . user . type === 'Bot' &&
! comment . body . includes ( '<details>' ) &&
! comment . body . includes ( 'Previous bot comment' )
2024-09-28 06:52:23 -06:00
) ;
2025-01-10 04:01:31 -07:00
for ( const comment of unhiddenBotComments ) {
2024-09-28 06:52:23 -06:00
// Don't format string - it will broke the markdown
const hiddenBody = `
< details >
< summary > Previous bot comment ( click to expand ) < / s u m m a r y >
$ { comment . body }
< / d e t a i l s > ` ;
await github . rest . issues . updateComment ( {
owner : context . repo . owner ,
repo : context . repo . repo ,
comment _id : comment . id ,
body : hiddenBody ,
} ) ;
}
} ;
2024-08-21 01:55:45 -06:00
module . exports = handleIssue ;