From 5e82956fcd5f5ffd1efee46ed0237f8297170c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20P=C4=99dzich?= Date: Fri, 27 Jan 2023 14:22:17 +0100 Subject: [PATCH] Show a rename warning for valid playlist URLs --- bot.ts | 74 +++++++++++++++++++++++------------------ getPlaylistIdFromUrl.ts | 19 +++++++++++ run.ts | 2 +- 3 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 getPlaylistIdFromUrl.ts diff --git a/bot.ts b/bot.ts index f37c337..93bee71 100644 --- a/bot.ts +++ b/bot.ts @@ -1,19 +1,21 @@ import { ApplicationFunction } from 'probot'; import getMetaData from 'metadata-scraper'; +import { getPlaylistIdFromUrl } from './getPlaylistIdFromUrl'; + type ReviewEvent = 'REQUEST_CHANGES' | 'COMMENT' | 'APPROVE'; -const bot: ApplicationFunction = (app) => { +export const bot: ApplicationFunction = (app) => { app.on( ['pull_request.opened', 'pull_request.synchronize'], - async (context) => { + async ({ payload, octokit }) => { const registryDirectoryPath = 'playlists/registry/'; const siQueryStart = '?si='; - const pull_number = context.payload.number; + const pull_number = payload.number; const workingRepo = { - owner: context.payload.repository.owner.login, - repo: context.payload.repository.name + owner: payload.repository.owner.login, + repo: payload.repository.name }; const repoAllowlist = [ @@ -30,14 +32,14 @@ const bot: ApplicationFunction = (app) => { event: ReviewEvent ) => { if (review_id) { - await context.octokit.pulls.updateReview({ + await octokit.pulls.updateReview({ ...workingRepo, pull_number, review_id, body }); } else { - await context.octokit.pulls.createReview({ + await octokit.pulls.createReview({ ...workingRepo, pull_number, event, @@ -54,7 +56,7 @@ const bot: ApplicationFunction = (app) => { if (!isAllowlistedRepo) return; - const { data: prFiles } = await context.octokit.pulls.listFiles({ + const { data: prFiles } = await octokit.pulls.listFiles({ ...workingRepo, pull_number }); @@ -69,18 +71,22 @@ const bot: ApplicationFunction = (app) => { const playlistLookupResults = await Promise.all( filesToVerify.map(async ({ filename }) => { const filenameWithoutPath = removePathFromFilename(filename); - const url = `https://open.spotify.com/playlist/${filenameWithoutPath}`; - const expectedStatusCodes = [200, 404]; + + const url = getPlaylistIdFromUrl(filename) + ? filename + : `https://open.spotify.com/playlist/${filenameWithoutPath}`; const spotifyResponse = await fetch(url); + const expectedStatusCodes = [200, 404]; - if (!expectedStatusCodes.includes(spotifyResponse.status)) + if (!expectedStatusCodes.includes(spotifyResponse.status)) { throw new Error( - `${spotifyResponse.url} responded with code ${spotifyResponse.status}` + `${spotifyResponse.url} responded with ${spotifyResponse.status}` ); + } const found = spotifyResponse.status === 200; - let info: string | null = null; + let info = ''; if (found) { const html = await spotifyResponse.text(); @@ -105,15 +111,17 @@ const bot: ApplicationFunction = (app) => { ({ found, filename }) => found && !filename.includes(siQueryStart) ); - const entriesWithSiQuery = playlistLookupResults.filter( - ({ found, filename }) => found && filename.includes(siQueryStart) + const entriesToRename = playlistLookupResults.filter( + ({ found, filename }) => + found && + (filename.includes(siQueryStart) || getPlaylistIdFromUrl(filename)) ); const notFoundPlaylists = playlistLookupResults.filter( ({ found }) => !found ); - const { data: priorReviews } = await context.octokit.pulls.listReviews({ + const { data: priorReviews } = await octokit.pulls.listReviews({ ...workingRepo, pull_number }); @@ -134,21 +142,15 @@ const bot: ApplicationFunction = (app) => { identifiedPlaylistsText = `### ✅ These playlists have been indentified:\n${playlistLinks}`; } - if (notFoundPlaylists.length > 0) { - const renameList = notFoundPlaylists - .map(({ filename }) => `- ${filename}`) - .join('\n'); - - successText = ''; - reviewEvent = 'REQUEST_CHANGES'; - notFoundText = `### ❌ Playlists for these entries don't exist:\n${renameList}`; - } - - if (entriesWithSiQuery.length > 0) { - const renameList = entriesWithSiQuery + if (entriesToRename.length > 0) { + const renameList = entriesToRename .map(({ filename }) => { + const playlistIdFromPossibleUrl = getPlaylistIdFromUrl(filename); const filenameWithoutPath = removePathFromFilename(filename); - const [targetFilename] = filenameWithoutPath.split(siQueryStart); + + const targetFilename = + playlistIdFromPossibleUrl || + filenameWithoutPath.replace(siQueryStart, ''); return `- From ${filenameWithoutPath} to **${targetFilename}**`; }) @@ -159,6 +161,16 @@ const bot: ApplicationFunction = (app) => { renameRequiredText = `### ⚠️ These entries have to be renamed:\n${renameList}`; } + if (notFoundPlaylists.length > 0) { + const renameList = notFoundPlaylists + .map(({ filename }) => `- ${filename}`) + .join('\n'); + + successText = ''; + reviewEvent = 'REQUEST_CHANGES'; + notFoundText = `### ❌ Playlists for these entries don't exist:\n${renameList}`; + } + const reviewBody = [ identifiedPlaylistsText, renameRequiredText, @@ -172,7 +184,7 @@ const bot: ApplicationFunction = (app) => { } catch (error) { console.error(error); - await context.octokit.pulls.createReview({ + await octokit.pulls.createReview({ ...workingRepo, pull_number, event: 'COMMENT', @@ -182,5 +194,3 @@ const bot: ApplicationFunction = (app) => { } ); }; - -export = bot; diff --git a/getPlaylistIdFromUrl.ts b/getPlaylistIdFromUrl.ts new file mode 100644 index 0000000..87a2024 --- /dev/null +++ b/getPlaylistIdFromUrl.ts @@ -0,0 +1,19 @@ +export const getPlaylistIdFromUrl = (url: string) => { + try { + const urlObject = new URL(url); + const [collectionName, playlistId] = urlObject.pathname + .split('/') + .filter(Boolean); + + const isValidPlaylistUrl = + urlObject.hostname === 'open.spotify.com' && + collectionName === 'playlist' && + playlistId; + + if (!isValidPlaylistUrl) return null; + + return playlistId; + } catch { + return null; + } +}; diff --git a/run.ts b/run.ts index c77cce8..722996d 100644 --- a/run.ts +++ b/run.ts @@ -1,4 +1,4 @@ import { run } from 'probot'; -import bot from './bot'; +import { bot } from './bot'; run(bot);