2022-09-21 22:39:54 +02:00
import getMetaData from 'metadata-scraper' ;
2022-09-12 12:45:19 +02:00
2023-01-27 14:22:17 +01:00
import { getPlaylistIdFromUrl } from './getPlaylistIdFromUrl' ;
2023-07-06 13:08:59 +02:00
import { Probot } from 'probot' ;
2023-01-27 14:22:17 +01:00
2022-10-09 15:02:17 +02:00
type ReviewEvent = 'REQUEST_CHANGES' | 'COMMENT' | 'APPROVE' ;
2023-07-06 13:08:59 +02:00
export const appFn = ( app : Probot ) = > {
2022-09-12 20:58:06 +02:00
app . on (
[ 'pull_request.opened' , 'pull_request.synchronize' ] ,
2023-01-27 14:22:17 +01:00
async ( { payload , octokit } ) = > {
2022-09-12 20:58:06 +02:00
const registryDirectoryPath = 'playlists/registry/' ;
const siQueryStart = '?si=' ;
2022-09-13 15:32:52 +02:00
2023-01-27 14:22:17 +01:00
const pull_number = payload . number ;
2022-09-21 22:39:54 +02:00
const workingRepo = {
2023-01-27 14:22:17 +01:00
owner : payload.repository.owner.login ,
repo : payload.repository.name
2022-09-12 20:58:06 +02:00
} ;
2023-01-27 15:39:28 +01:00
const removeRegistryPathFromFilename = ( filename : string ) = >
2022-09-12 20:58:06 +02:00
filename . replace ( registryDirectoryPath , '' ) ;
2022-09-21 22:39:54 +02:00
const upsertReview = async (
review_id : number | undefined ,
2023-01-27 15:39:28 +01:00
event : ReviewEvent ,
body : string
2022-09-21 22:39:54 +02:00
) = > {
2022-09-12 20:58:06 +02:00
if ( review_id ) {
2023-01-27 14:22:17 +01:00
await octokit . pulls . updateReview ( {
2022-09-21 22:39:54 +02:00
. . . workingRepo ,
2022-09-12 20:58:06 +02:00
pull_number ,
review_id ,
body
} ) ;
} else {
2023-01-27 14:22:17 +01:00
await octokit . pulls . createReview ( {
2022-09-21 22:39:54 +02:00
. . . workingRepo ,
2022-09-12 20:58:06 +02:00
pull_number ,
2022-09-21 22:39:54 +02:00
event ,
body
2022-09-12 20:58:06 +02:00
} ) ;
}
} ;
try {
2023-02-23 18:48:41 +01:00
const repoAllowlist = [
{ owner : 'mackorone' , repo : 'spotify-playlist-archive' } ,
{ owner : 'maciejpedzich' , repo : 'bot-testing-ground' }
] ;
2022-12-23 14:46:07 +01:00
const isAllowlistedRepo = repoAllowlist . find (
2022-09-14 06:53:05 +02:00
( { owner , repo } ) = >
2022-09-21 22:39:54 +02:00
workingRepo . owner === owner && workingRepo . repo === repo
2022-09-14 06:53:05 +02:00
) ;
2022-12-23 14:46:07 +01:00
if ( ! isAllowlistedRepo ) return ;
2022-09-14 06:53:05 +02:00
2023-01-27 14:22:17 +01:00
const { data : prFiles } = await octokit . pulls . listFiles ( {
2022-09-21 22:39:54 +02:00
. . . workingRepo ,
2022-09-12 20:58:06 +02:00
pull_number
} ) ;
const filesToVerify = prFiles . filter (
( { status , filename } ) = >
2023-02-23 18:48:41 +01:00
filename . startsWith ( registryDirectoryPath ) &&
[ 'added' , 'modified' ] . includes ( status )
2022-09-12 20:58:06 +02:00
) ;
2022-12-23 14:46:07 +01:00
if ( filesToVerify . length === 0 ) return ;
2023-02-23 18:48:41 +01:00
const playlistSearchResults = await Promise . all (
2022-09-12 20:58:06 +02:00
filesToVerify . map ( async ( { filename } ) = > {
2023-01-27 15:39:28 +01:00
const filenameWithoutRegistryPath = removeRegistryPathFromFilename (
filename
) . replace ( 'https:/' , 'https://' ) ;
2023-01-27 14:22:17 +01:00
2023-01-27 15:39:28 +01:00
const url = getPlaylistIdFromUrl ( filenameWithoutRegistryPath )
2023-01-27 15:48:17 +01:00
? filenameWithoutRegistryPath
2023-01-27 15:39:28 +01:00
: ` https://open.spotify.com/playlist/ ${ filenameWithoutRegistryPath } ` ;
2022-09-21 22:39:54 +02:00
const spotifyResponse = await fetch ( url ) ;
2023-02-23 18:48:41 +01:00
const expectedStatusCodes = [ 200 , 400 , 404 ] ;
2022-09-22 06:14:31 +02:00
2023-01-27 14:22:17 +01:00
if ( ! expectedStatusCodes . includes ( spotifyResponse . status ) ) {
2023-02-23 18:48:41 +01:00
throw new Error ( ` Spotify ${ spotifyResponse . status } ` ) ;
2023-01-27 14:22:17 +01:00
}
2022-12-23 14:46:07 +01:00
const found = spotifyResponse . status === 200 ;
2023-02-02 17:01:45 +01:00
let details = '' ;
2022-09-21 22:39:54 +02:00
if ( found ) {
const html = await spotifyResponse . text ( ) ;
const { title , description } = await getMetaData ( { html } ) ;
const playlistMeta = ( description || '' )
. split ( ' · ' )
. filter ( ( text ) = > text !== 'Playlist' ) ;
2023-02-02 17:01:45 +01:00
details = [ title , . . . playlistMeta ] . join ( ' · ' ) ;
2022-09-21 22:39:54 +02:00
}
2022-09-12 20:58:06 +02:00
return {
2023-01-27 15:39:28 +01:00
filename : filenameWithoutRegistryPath ,
2022-09-21 22:39:54 +02:00
found ,
2023-02-02 17:01:45 +01:00
details ,
2022-09-21 22:39:54 +02:00
url
2022-09-12 20:58:06 +02:00
} ;
} )
) ;
2023-01-27 15:39:28 +01:00
let successText = ` 🎉 @ ${ workingRepo . owner } can merge your pull request! 🎉 ` ;
let reviewEvent : ReviewEvent = 'APPROVE' ;
let identifiedPlaylistsText = '' ;
2023-02-23 18:48:41 +01:00
const validEntries = playlistSearchResults . filter (
2023-02-02 17:46:58 +01:00
( { found , filename , url } ) = >
found && ! filename . includes ( siQueryStart ) && filename !== url
2022-09-21 22:39:54 +02:00
) ;
if ( validEntries . length > 0 ) {
const playlistLinks = validEntries
2023-02-02 17:01:45 +01:00
. map ( ( { url , details } ) = > ` - [ ${ details } ]( ${ url } ) ` )
2022-09-21 22:39:54 +02:00
. join ( '\n' ) ;
2022-12-23 14:46:07 +01:00
identifiedPlaylistsText = ` ### ✅ These playlists have been indentified: \ n ${ playlistLinks } ` ;
2022-09-21 22:39:54 +02:00
}
2022-09-12 20:58:06 +02:00
2023-02-02 17:01:45 +01:00
let renameRequiredText = '' ;
2023-02-23 18:48:41 +01:00
const entriesToRename = playlistSearchResults . filter (
2023-01-27 15:39:28 +01:00
( { found , filename } ) = >
found &&
2023-01-28 12:43:06 +01:00
filename . includes ( siQueryStart ) &&
! getPlaylistIdFromUrl ( filename )
2023-01-27 15:39:28 +01:00
) ;
2023-02-02 17:01:45 +01:00
if ( entriesToRename . length > 0 ) {
const renameList = entriesToRename
2022-09-13 10:03:48 +02:00
. map ( ( { filename } ) = > {
2023-01-28 12:43:06 +01:00
const filenameWithoutRegistryPath =
2023-01-27 15:39:28 +01:00
removeRegistryPathFromFilename ( filename ) ;
2023-01-27 14:22:17 +01:00
2023-01-28 12:43:06 +01:00
const [ targetFilename ] =
filenameWithoutRegistryPath . split ( siQueryStart ) ;
2022-09-13 10:03:48 +02:00
2023-01-28 12:43:06 +01:00
return ` - From \` ${ filenameWithoutRegistryPath } \` to ** ${ targetFilename } ** ` ;
2022-09-13 10:03:48 +02:00
} )
. join ( '\n' ) ;
2022-09-21 22:39:54 +02:00
successText = '' ;
reviewEvent = 'REQUEST_CHANGES' ;
2023-02-02 17:01:45 +01:00
renameRequiredText = ` ### ⚠️ You have to rename these entries: \ n ${ renameList } ` ;
2023-01-28 12:43:06 +01:00
}
let urlEntriesToRenameText = '' ;
2023-02-23 18:48:41 +01:00
const urlFilenameEntries = playlistSearchResults . filter (
2023-02-02 17:01:45 +01:00
( { filename , url } ) = > filename === url
2023-01-28 12:43:06 +01:00
) ;
if ( urlFilenameEntries . length > 0 ) {
successText = '' ;
2023-02-02 17:01:45 +01:00
2023-02-02 17:46:58 +01:00
const forkPageUrl = payload . pull_request . head . repo . html_url ;
const httpsDirUrl = ` ${ forkPageUrl } /tree/main/playlists/registry/https: ` ;
const baseCreateUrl = ` ${ forkPageUrl } /new/main/playlists/registry/FOO ` ;
2023-02-02 17:01:45 +01:00
const linkList = urlFilenameEntries . map ( ( { url } ) = > {
const playlistId = getPlaylistIdFromUrl ( url ) ;
2023-02-02 17:46:58 +01:00
const createFilePageUrl = ` ${ baseCreateUrl } ?filename= ${ playlistId } &value=REMOVE%20THIS%20TEXT%20FIRST ` ;
2023-02-02 17:01:45 +01:00
return ` \ t- [Create \` ${ playlistId } \` ]( ${ createFilePageUrl } ) ` ;
} ) ;
2023-01-28 12:43:06 +01:00
reviewEvent = 'REQUEST_CHANGES' ;
2023-02-02 17:46:58 +01:00
urlEntriesToRenameText = ` ### ⚠️ Some entries are malformed playlist URLs \ n \ nHere's how you can correct them: \ n \ n1. Go to [the \` https: \` folder]( ${ httpsDirUrl } ), click on the three dots on the right-hand side, and choose _Delete directory_ \ n \ n2. Use the links below to create valid entries: \ n ${ linkList } ` ;
2022-09-21 22:39:54 +02:00
}
2022-09-12 20:58:06 +02:00
2023-01-27 15:39:28 +01:00
let notFoundText = '' ;
2023-02-23 18:48:41 +01:00
const notFoundPlaylists = playlistSearchResults . filter (
2023-01-27 15:39:28 +01:00
( { found } ) = > ! found
) ;
2023-01-27 14:22:17 +01:00
if ( notFoundPlaylists . length > 0 ) {
2023-02-02 17:01:45 +01:00
const notFoundList = notFoundPlaylists
2023-01-27 14:22:17 +01:00
. map ( ( { filename } ) = > ` - ${ filename } ` )
. join ( '\n' ) ;
successText = '' ;
reviewEvent = 'REQUEST_CHANGES' ;
2023-02-02 17:01:45 +01:00
notFoundText = ` ### ❌ These entries don't point to any existing public playlists: \ n ${ notFoundList } ` ;
2023-01-27 14:22:17 +01:00
}
2022-09-21 22:39:54 +02:00
const reviewBody = [
identifiedPlaylistsText ,
2023-02-02 17:01:45 +01:00
renameRequiredText ,
2023-01-28 12:43:06 +01:00
urlEntriesToRenameText ,
2022-09-21 22:39:54 +02:00
notFoundText ,
successText
]
. filter ( Boolean )
. join ( '\n\n' ) ;
2023-01-27 15:39:28 +01:00
const { data : reviews } = await octokit . pulls . listReviews ( {
2022-09-21 22:39:54 +02:00
. . . workingRepo ,
2023-01-27 15:39:28 +01:00
pull_number
2022-09-12 20:58:06 +02:00
} ) ;
2023-01-27 15:39:28 +01:00
const [ existingReview ] = reviews ;
await upsertReview ( existingReview ? . id , reviewEvent , reviewBody ) ;
} catch ( error ) {
console . error ( error ) ;
await upsertReview (
undefined ,
'COMMENT' ,
` Something went wrong while validating new entries! @ ${ workingRepo . owner } should handle it shortly... `
) ;
2022-09-12 20:58:06 +02:00
}
}
) ;
2022-09-12 12:45:19 +02:00
} ;