diff --git a/packages/tools/tool-utils.ts b/packages/tools/tool-utils.ts index 9ef09fd85..fb500927a 100644 --- a/packages/tools/tool-utils.ts +++ b/packages/tools/tool-utils.ts @@ -6,6 +6,20 @@ const execa = require('execa'); const { splitCommandString } = require('@joplin/lib/string-utils'); const moment = require('moment'); +export interface GitHubReleaseAsset { + name: string; + browser_download_url: string; +} + +export interface GitHubRelease { + assets: GitHubReleaseAsset[]; + tag_name: string; + upload_url: string; + html_url: string; + prerelease: boolean; + draft: boolean; +} + function quotePath(path: string) { if (!path) return ''; if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path; @@ -364,7 +378,39 @@ export function githubOauthToken() { return readCredentialFile('github_oauth_token.txt'); } -export async function githubRelease(project: string, tagName: string, options: any = null) { +// Note that the GitHub API releases/latest is broken on the joplin-android repo +// as of Nov 2021 (last working on 3 November 2021, first broken on 19 +// November). It used to return the latest **published** release but now it +// retuns... some release, always the same one, but not the latest one. GitHub +// says that nothing has changed on the API, although it used to work. So since +// we can't use /latest anymore, we need to fetch all the releases to find the +// latest published one. +export async function gitHubLatestRelease(repoName: string): Promise { + let pageNum = 1; + + while (true) { + const response: any = await fetch(`https://api.github.com/repos/laurent22/${repoName}/releases?page=${pageNum}`, { + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'Joplin Readme Updater', + }, + }); + + if (!response.ok) throw new Error(`Cannot fetch releases: ${response.statusText}`); + + const releases = await response.json(); + if (!releases.length) throw new Error('Cannot find latest release'); + + for (const release of releases) { + if (release.prerelease || release.draft) continue; + return release; + } + + pageNum++; + } +} + +export async function githubRelease(project: string, tagName: string, options: any = null): Promise { options = Object.assign({}, { isDraft: false, isPreRelease: false, diff --git a/packages/tools/update-readme-download.ts b/packages/tools/update-readme-download.ts index 003b771fa..22f18cafe 100644 --- a/packages/tools/update-readme-download.ts +++ b/packages/tools/update-readme-download.ts @@ -1,18 +1,8 @@ import * as fs from 'fs-extra'; import { fileExtension } from '@joplin/lib/path-utils'; -const request = require('request'); +import { gitHubLatestRelease, GitHubRelease } from './tool-utils'; const readmePath = `${__dirname}/../../README.md`; -interface GitHubReleaseAsset { - name: string; - browser_download_url: string; -} - -interface GitHubRelease { - assets: GitHubReleaseAsset[]; - tag_name: string; -} - async function msleep(ms: number) { return new Promise((resolve) => { setTimeout(() => { @@ -21,25 +11,6 @@ async function msleep(ms: number) { }); } -async function gitHubLatestRelease(repoName: string): Promise { - return new Promise((resolve, reject) => { - request.get({ - url: `https://api.github.com/repos/laurent22/${repoName}/releases/latest`, - json: true, - headers: { 'User-Agent': 'Joplin Readme Updater' }, - }, (error: any, response: any, data: any) => { - if (error) { - reject(error); - } else if (response.statusCode !== 200) { - console.warn(data); - reject(new Error(`Error HTTP ${response.statusCode}`)); - } else { - resolve(data); - } - }); - }); -} - function downloadUrl(release: GitHubRelease, os: string, portable = false) { if (!release || !release.assets || !release.assets.length) return null; @@ -122,8 +93,8 @@ async function main(argv: any) { // Disable for now due to broken /latest API end point, which returns a // version from 6 months ago. - // if (androidUrl) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin-android\/releases\/download\/android-v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+\.apk)/, androidUrl); - // if (android32Url) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin-android\/releases\/download\/android-v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+-32bit\.apk)/, android32Url); + if (androidUrl) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin-android\/releases\/download\/android-v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+\.apk)/, androidUrl); + if (android32Url) content = content.replace(/(https:\/\/github.com\/laurent22\/joplin-android\/releases\/download\/android-v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+-32bit\.apk)/, android32Url); setReadmeContent(content);