mirror of https://github.com/sualko/cloud_bbb
chore: refactor build and publish script
- use typescript - create changelog during build - include changelog in archivepull/126/head
parent
dc756acd2b
commit
5be06d6ef9
|
@ -70,6 +70,7 @@
|
||||||
"@nextcloud/eslint-plugin": "^2.0.0",
|
"@nextcloud/eslint-plugin": "^2.0.0",
|
||||||
"@nextcloud/files": "^1.0.1",
|
"@nextcloud/files": "^1.0.1",
|
||||||
"@types/bootstrap": "^4.3.2",
|
"@types/bootstrap": "^4.3.2",
|
||||||
|
"@types/inquirer": "^7.3.1",
|
||||||
"@types/jquery": "^3.3.35",
|
"@types/jquery": "^3.3.35",
|
||||||
"@types/node": "^14.6.2",
|
"@types/node": "^14.6.2",
|
||||||
"@types/react": "^16.9.34",
|
"@types/react": "^16.9.34",
|
||||||
|
|
|
@ -1,27 +1,45 @@
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
import colors from 'colors';
|
||||||
require('colors').setTheme({
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
import simpleGit from 'simple-git/promise';
|
||||||
|
import libxml from 'libxmljs';
|
||||||
|
import https from 'https';
|
||||||
|
import archiver from 'archiver';
|
||||||
|
import execa from 'execa';
|
||||||
|
import {exec} from 'child_process';
|
||||||
|
import { generateChangelog, hasChangeLogEntry } from './imports/changelog';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const packageInfo = require('../package.json');
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface String {
|
||||||
|
error: string
|
||||||
|
verbose: string
|
||||||
|
warn: string
|
||||||
|
green: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colors.setTheme({
|
||||||
verbose: 'cyan',
|
verbose: 'cyan',
|
||||||
warn: 'yellow',
|
warn: 'yellow',
|
||||||
error: 'red',
|
error: 'red',
|
||||||
});
|
});
|
||||||
|
|
||||||
const fs = require('fs');
|
const git = simpleGit();
|
||||||
const path = require('path');
|
|
||||||
const libxml = require('libxmljs');
|
|
||||||
const https = require('https');
|
|
||||||
const archiver = require('archiver');
|
|
||||||
const execa = require('execa');
|
|
||||||
const git = require('simple-git/promise')();
|
|
||||||
const package = require('../package.json');
|
|
||||||
|
|
||||||
const infoXmlPath = './appinfo/info.xml';
|
const infoXmlPath = './appinfo/info.xml';
|
||||||
const isStableRelease = process.argv.indexOf('--stable') > 1;
|
const isStableRelease = process.argv.indexOf('--stable') > 1;
|
||||||
|
const isDryRun = process.argv.indexOf('--dry-run') > 1;
|
||||||
|
|
||||||
async function getVersion() {
|
async function getVersion() {
|
||||||
return package.version + (!isStableRelease ? '-git.' + (await git.raw(['rev-parse', '--short', 'HEAD'])).trim() : '');
|
return packageInfo.version + (!isStableRelease ? '-git.' + (await git.raw(['rev-parse', '--short', 'HEAD'])).trim() : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
run();
|
run().catch(err => {
|
||||||
|
console.log(`✘ ${err.toString()}`.error);
|
||||||
|
});
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const appId = await prepareInfoXml();
|
const appId = await prepareInfoXml();
|
||||||
|
@ -55,6 +73,9 @@ async function createRelease(appId) {
|
||||||
const version = await getVersion();
|
const version = await getVersion();
|
||||||
console.log(`I'm now building ${appId} in version ${version}.`.verbose);
|
console.log(`I'm now building ${appId} in version ${version}.`.verbose);
|
||||||
|
|
||||||
|
await isRepoClean();
|
||||||
|
console.log('✔ repo is clean'.green);
|
||||||
|
|
||||||
await execa('yarn', ['composer:install:dev']);
|
await execa('yarn', ['composer:install:dev']);
|
||||||
console.log('✔ composer dev dependencies installed'.green);
|
console.log('✔ composer dev dependencies installed'.green);
|
||||||
|
|
||||||
|
@ -67,6 +88,8 @@ async function createRelease(appId) {
|
||||||
await execa('yarn', ['build']);
|
await execa('yarn', ['build']);
|
||||||
console.log('✔ scripts built'.green);
|
console.log('✔ scripts built'.green);
|
||||||
|
|
||||||
|
await updateChangelog();
|
||||||
|
|
||||||
const filePath = await createArchive(appId, appId + '-v' + version);
|
const filePath = await createArchive(appId, appId + '-v' + version);
|
||||||
await createNextcloudSignature(appId, filePath);
|
await createNextcloudSignature(appId, filePath);
|
||||||
await createGPGSignature(filePath);
|
await createGPGSignature(filePath);
|
||||||
|
@ -76,6 +99,64 @@ async function createRelease(appId) {
|
||||||
console.log('✔ composer dev dependencies installed'.green);
|
console.log('✔ composer dev dependencies installed'.green);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function isRepoClean() {
|
||||||
|
const status = await git.status();
|
||||||
|
|
||||||
|
if (status.staged.length > 0) {
|
||||||
|
throw 'Repo not clean. Found staged files.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.modified.length > 2 || !status.modified.includes('package.json') || !status.modified.includes('appinfo/info.xml')) {
|
||||||
|
throw 'Repo not clean. Found modified files.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.not_added.length > 0) {
|
||||||
|
throw 'Repo not clean. Found not added files.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateChangelog() {
|
||||||
|
if (!isStableRelease) {
|
||||||
|
console.log('Skip changelog for non-stable releases.'.warn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeLog = await generateChangelog(packageInfo.version);
|
||||||
|
console.log('✔ change log generated'.green);
|
||||||
|
|
||||||
|
console.log(changeLog);
|
||||||
|
|
||||||
|
console.log('Press any key to continue...');
|
||||||
|
await keypress();
|
||||||
|
|
||||||
|
await hasChangeLogEntry(packageInfo.version);
|
||||||
|
console.log('✔ there is a change log entry for this version'.green);
|
||||||
|
|
||||||
|
await commitChangeLog();
|
||||||
|
console.log('✔ change log commited'.green);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function keypress() {
|
||||||
|
return inquirer.prompt([{
|
||||||
|
type: 'input',
|
||||||
|
name: 'keypress',
|
||||||
|
message: 'Press any key to continue... (where is the any key?)',
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function commitChangeLog(): Promise<void> {
|
||||||
|
const status = await git.status();
|
||||||
|
|
||||||
|
if (status.staged.length > 0) {
|
||||||
|
throw 'Repo not clean. Found staged files.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDryRun) {
|
||||||
|
await git.add('CHANGELOG.md');
|
||||||
|
await git.commit('docs: update change log', ['-n']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function createArchive(appId, fileBaseName) {
|
function createArchive(appId, fileBaseName) {
|
||||||
const fileName = `${fileBaseName}.tar.gz`;
|
const fileName = `${fileBaseName}.tar.gz`;
|
||||||
|
@ -135,11 +216,7 @@ function createArchive(appId, fileBaseName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNextcloudSignature(appId, filePath) {
|
function createNextcloudSignature(appId, filePath) {
|
||||||
const {
|
return new Promise<void>((resolve) => {
|
||||||
exec,
|
|
||||||
} = require('child_process');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const sigPath = filePath + '.ncsig';
|
const sigPath = filePath + '.ncsig';
|
||||||
exec(`openssl dgst -sha512 -sign ~/.nextcloud/certificates/${appId}.key ${filePath} | openssl base64 > ${sigPath}`, (error, stdout, stderr) => {
|
exec(`openssl dgst -sha512 -sign ~/.nextcloud/certificates/${appId}.key ${filePath} | openssl base64 > ${sigPath}`, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -162,11 +239,7 @@ function createNextcloudSignature(appId, filePath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGPGSignature(filePath) {
|
function createGPGSignature(filePath) {
|
||||||
const {
|
return new Promise<void>((resolve) => {
|
||||||
exec,
|
|
||||||
} = require('child_process');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
exec(`gpg --yes --detach-sign "${filePath}"`, (error, stdout, stderr) => {
|
exec(`gpg --yes --detach-sign "${filePath}"`, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -188,11 +261,7 @@ function createGPGSignature(filePath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGPGArmorSignature(filePath) {
|
function createGPGArmorSignature(filePath) {
|
||||||
const {
|
return new Promise<void>((resolve) => {
|
||||||
exec,
|
|
||||||
} = require('child_process');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
exec(`gpg --yes --detach-sign --armor "${filePath}"`, (error, stdout, stderr) => {
|
exec(`gpg --yes --detach-sign --armor "${filePath}"`, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -220,9 +289,10 @@ async function validateXml(xmlDoc) {
|
||||||
throw 'Found no schema location';
|
throw 'Found no schema location';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let schemaString: string;
|
||||||
let schemaString;
|
|
||||||
try {
|
try {
|
||||||
|
console.log('Downloading schema file...'.verbose);
|
||||||
|
|
||||||
schemaString = await wget(schemaLocation);
|
schemaString = await wget(schemaLocation);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Could not download schema. Skip validation.'.warn);
|
console.log('Could not download schema. Skip validation.'.warn);
|
||||||
|
@ -245,8 +315,8 @@ async function validateXml(xmlDoc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wget(url) {
|
function wget(url: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
https.get(url, (resp) => {
|
https.get(url, (resp) => {
|
||||||
let data = '';
|
let data = '';
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
import simpleGit from 'simple-git/promise';
|
||||||
|
|
||||||
|
const git = simpleGit();
|
||||||
|
|
||||||
|
export async function generateChangelog(version: string): Promise<string> {
|
||||||
|
const latestTag = (await git.tags()).latest;
|
||||||
|
const title = `v${version}` === latestTag ? '[Unreleased]' : `${version} (${new Date().toISOString().split('T')[0]})`;
|
||||||
|
|
||||||
|
const logs = await git.log({
|
||||||
|
from: latestTag,
|
||||||
|
to: 'HEAD',
|
||||||
|
});
|
||||||
|
|
||||||
|
const sections = [{
|
||||||
|
type: 'feat',
|
||||||
|
label: 'Added',
|
||||||
|
}, {
|
||||||
|
type: 'fix',
|
||||||
|
label: 'Fixed',
|
||||||
|
}];
|
||||||
|
|
||||||
|
const entries = {};
|
||||||
|
|
||||||
|
logs.all.forEach(log => {
|
||||||
|
const match = log.message.match(/^([a-z]+)(?:\((\w+)\))?: (.+)/);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, type, scope, description] = match;
|
||||||
|
const entry = { type, scope, description, issues: <string[]> [] };
|
||||||
|
|
||||||
|
if(log.body) {
|
||||||
|
const matches = log.body.match(/(?:fix|fixes|closes?|refs?) #(\d+)/g) || [];
|
||||||
|
|
||||||
|
for (const match of matches) {
|
||||||
|
const [, number] = <RegExpMatchArray> match.match(/(\d+)$/);
|
||||||
|
|
||||||
|
entry.issues.push(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entries[type]) {
|
||||||
|
entries[type] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
entries[type].push(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
let changeLog = `## ${title}\n`;
|
||||||
|
|
||||||
|
function stringifyEntry(entry) {
|
||||||
|
const issues = entry.issues.map(issue => {
|
||||||
|
return `[#${issue}](https://github.com/sualko/cloud_bbb/issues/${issue})`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
return `- ${issues}${issues.length > 0 ? ' ' : ''}${entry.description}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.forEach(section => {
|
||||||
|
if (!entries[section.type]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLog += `### ${section.label}\n`;
|
||||||
|
|
||||||
|
entries[section.type].forEach(entry => {
|
||||||
|
changeLog += stringifyEntry(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
delete entries[section.type];
|
||||||
|
|
||||||
|
changeLog += '\n';
|
||||||
|
});
|
||||||
|
|
||||||
|
const miscKeys = Object.keys(entries);
|
||||||
|
|
||||||
|
if (miscKeys && miscKeys.length > 0) {
|
||||||
|
changeLog += '### Misc\n';
|
||||||
|
|
||||||
|
miscKeys.forEach(type => {
|
||||||
|
entries[type].forEach(entry => {
|
||||||
|
changeLog += stringifyEntry(entry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return changeLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editChangeLog(changeLog: string):Promise<string> {
|
||||||
|
const answers = await inquirer.prompt([{
|
||||||
|
type: 'editor',
|
||||||
|
name: 'changeLog',
|
||||||
|
message: 'You have now the possibility to edit the change log',
|
||||||
|
default: changeLog,
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return answers.changeLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hasChangeLogEntry(version: string): Promise<boolean> {
|
||||||
|
const entry = await getChangelogEntry(version);
|
||||||
|
|
||||||
|
return entry.split('\n').filter(line => !!line.trim()).length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChangelogEntry(version: string): Promise<string> {
|
||||||
|
return new Promise<string>(resolve => {
|
||||||
|
fs.readFile(path.join(__dirname, '..', 'CHANGELOG.md'), 'utf8', function (err, data) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
const releaseHeader = /^\d+\.\d+\.\d+$/.test(version) ? `## ${version}` : '## [Unreleased]';
|
||||||
|
const lines = data.split('\n');
|
||||||
|
const entry: string[] = [];
|
||||||
|
|
||||||
|
let inEntry = false;
|
||||||
|
|
||||||
|
for(const line of lines) {
|
||||||
|
if (line.startsWith(releaseHeader)) {
|
||||||
|
inEntry = true;
|
||||||
|
} else if (line.startsWith('## ') && entry.length > 0) {
|
||||||
|
inEntry = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inEntry) {
|
||||||
|
entry.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(entry.join('\n'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,29 +1,43 @@
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
import colors from 'colors';
|
||||||
require('colors').setTheme({
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
import simpleGit from 'simple-git/promise';
|
||||||
|
import https from 'https';
|
||||||
|
import execa from 'execa';
|
||||||
|
import {Octokit} from '@octokit/rest';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
import { getChangelogEntry, hasChangeLogEntry } from './imports/changelog';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const packageInfo = require('../package.json');
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface String {
|
||||||
|
error: string
|
||||||
|
verbose: string
|
||||||
|
warn: string
|
||||||
|
green: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colors.setTheme({
|
||||||
verbose: 'cyan',
|
verbose: 'cyan',
|
||||||
warn: 'yellow',
|
warn: 'yellow',
|
||||||
error: 'red',
|
error: 'red',
|
||||||
});
|
});
|
||||||
|
|
||||||
const fs = require('fs');
|
dotenv.config();
|
||||||
const path = require('path');
|
|
||||||
const https = require('https');
|
|
||||||
const { Octokit } = require('@octokit/rest');
|
|
||||||
const execa = require('execa');
|
|
||||||
const inquirer = require('inquirer');
|
|
||||||
const git = require('simple-git/promise')();
|
|
||||||
const package = require('../package.json');
|
|
||||||
|
|
||||||
require('dotenv').config();
|
|
||||||
|
|
||||||
|
const git = simpleGit();
|
||||||
const isDryRun = process.argv.indexOf('--dry-run') > 1;
|
const isDryRun = process.argv.indexOf('--dry-run') > 1;
|
||||||
const commitMessage = `release: ${package.version} :tada:`;
|
const commitMessage = `release: ${packageInfo.version} :tada:`;
|
||||||
const tagName = `v${package.version}`;
|
const tagName = `v${packageInfo.version}`;
|
||||||
const files = [
|
const files = [
|
||||||
path.join(__dirname, '..', 'archives', `bbb-v${package.version}.tar.gz`),
|
path.join(__dirname, '..', 'archives', `bbb-v${packageInfo.version}.tar.gz`),
|
||||||
path.join(__dirname, '..', 'archives', `bbb-v${package.version}.tar.gz.asc`),
|
path.join(__dirname, '..', 'archives', `bbb-v${packageInfo.version}.tar.gz.asc`),
|
||||||
path.join(__dirname, '..', 'archives', `bbb-v${package.version}.tar.gz.ncsig`),
|
path.join(__dirname, '..', 'archives', `bbb-v${packageInfo.version}.tar.gz.ncsig`),
|
||||||
path.join(__dirname, '..', 'archives', `bbb-v${package.version}.tar.gz.sig`),
|
path.join(__dirname, '..', 'archives', `bbb-v${packageInfo.version}.tar.gz.sig`),
|
||||||
];
|
];
|
||||||
|
|
||||||
function pull() {
|
function pull() {
|
||||||
|
@ -37,136 +51,11 @@ async function notAlreadyTagged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function lastCommitNotBuild() {
|
async function lastCommitNotBuild() {
|
||||||
return (await git.log(['-1'])).latest.message !== commitMessage;
|
return (await git.log(['-1'])).latest?.message !== commitMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isMasterBranch() {
|
async function isMasterBranch() {
|
||||||
return (await git.branch()) === 'master';
|
return (await git.branch()).current === 'master';
|
||||||
}
|
|
||||||
|
|
||||||
async function generateChangelog() {
|
|
||||||
const latestTag = (await git.tags()).latest;
|
|
||||||
const title = `v${package.version}` === latestTag ? '[Unreleased]' : `${package.version} (${new Date().toISOString().split('T')[0]})`;
|
|
||||||
|
|
||||||
const logs = await git.log({
|
|
||||||
from: latestTag,
|
|
||||||
to: 'HEAD',
|
|
||||||
});
|
|
||||||
|
|
||||||
const sections = [{
|
|
||||||
type: 'feat',
|
|
||||||
label: 'Added',
|
|
||||||
}, {
|
|
||||||
type: 'fix',
|
|
||||||
label: 'Fixed',
|
|
||||||
}];
|
|
||||||
|
|
||||||
const entries = {};
|
|
||||||
|
|
||||||
logs.all.forEach(log => {
|
|
||||||
const match = log.message.match(/^([a-z]+)(?:\((\w+)\))?: (.+)/);
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [, type, scope, description] = match;
|
|
||||||
const entry = { type, scope, description, issues: [] };
|
|
||||||
|
|
||||||
if(log.body) {
|
|
||||||
const matches = log.body.match(/(?:fix|fixes|closes?|refs?) #(\d+)/g) || [];
|
|
||||||
|
|
||||||
for (const match of matches) {
|
|
||||||
const [, number] = match.match(/(\d+)$/);
|
|
||||||
|
|
||||||
entry.issues.push(number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entries[type]) {
|
|
||||||
entries[type] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[type].push(entry);
|
|
||||||
});
|
|
||||||
|
|
||||||
let changeLog = `## ${title}\n`;
|
|
||||||
|
|
||||||
function stringifyEntry(entry) {
|
|
||||||
const issues = entry.issues.map(issue => {
|
|
||||||
return `[#${issue}](https://github.com/sualko/cloud_bbb/issues/${issue})`;
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
return `- ${issues}${issues.length > 0 ? ' ' : ''}${entry.description}\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
sections.forEach(section => {
|
|
||||||
if (!entries[section.type]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
changeLog += `### ${section.label}\n`;
|
|
||||||
|
|
||||||
entries[section.type].forEach(entry => {
|
|
||||||
changeLog += stringifyEntry(entry);
|
|
||||||
});
|
|
||||||
|
|
||||||
delete entries[section.type];
|
|
||||||
|
|
||||||
changeLog += '\n';
|
|
||||||
});
|
|
||||||
|
|
||||||
const miscKeys = Object.keys(entries);
|
|
||||||
|
|
||||||
if (miscKeys && miscKeys.length > 0) {
|
|
||||||
changeLog += '### Misc\n';
|
|
||||||
|
|
||||||
miscKeys.forEach(type => {
|
|
||||||
entries[type].forEach(entry => {
|
|
||||||
changeLog += stringifyEntry(entry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return changeLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function editChangeLog(changeLog) {
|
|
||||||
const answers = await inquirer.prompt([{
|
|
||||||
type: 'editor',
|
|
||||||
name: 'changeLog',
|
|
||||||
message: 'You have now the possibility to edit the change log',
|
|
||||||
default: changeLog,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
return answers.changeLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasChangeLogEntry() {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
fs.readFile(path.join(__dirname, '..', 'CHANGELOG.md'), function (err, data) {
|
|
||||||
if (err) throw err;
|
|
||||||
|
|
||||||
if (!data.includes(`## ${package.version}`) && /^\d+\.\d+\.\d+$/.test(package.version)) {
|
|
||||||
throw `Found no change log entry for ${package.version}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function commitChangeLog() {
|
|
||||||
const status = await git.status();
|
|
||||||
|
|
||||||
if (status.staged.length > 0) {
|
|
||||||
throw 'Repo not clean. Found staged files.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDryRun) {
|
|
||||||
await git.add('CHANGELOG.md');
|
|
||||||
await git.commit('docs: update change log', ['-n']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasArchiveAndSignatures() {
|
async function hasArchiveAndSignatures() {
|
||||||
|
@ -180,7 +69,7 @@ async function stageAllFiles() {
|
||||||
|
|
||||||
const gitProcess = execa('git', ['add', '-u']);
|
const gitProcess = execa('git', ['add', '-u']);
|
||||||
|
|
||||||
gitProcess.stdout.pipe(process.stdout);
|
gitProcess.stdout?.pipe(process.stdout);
|
||||||
|
|
||||||
return gitProcess;
|
return gitProcess;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +77,7 @@ async function stageAllFiles() {
|
||||||
function showStagedDiff() {
|
function showStagedDiff() {
|
||||||
const gitProcess = execa('git', ['diff', '--staged']);
|
const gitProcess = execa('git', ['diff', '--staged']);
|
||||||
|
|
||||||
gitProcess.stdout.pipe(process.stdout);
|
gitProcess.stdout?.pipe(process.stdout);
|
||||||
|
|
||||||
return gitProcess;
|
return gitProcess;
|
||||||
}
|
}
|
||||||
|
@ -240,8 +129,8 @@ async function createGithubRelease(changeLog) {
|
||||||
userAgent: 'custom releaser for sualko/cloud_bbb',
|
userAgent: 'custom releaser for sualko/cloud_bbb',
|
||||||
});
|
});
|
||||||
|
|
||||||
const origin = (await git.remote(['get-url', 'origin'])).trim();
|
const origin = (await git.remote(['get-url', 'origin'])) || '';
|
||||||
const matches = origin.match(/^git@github\.com:(.+)\/(.+)\.git$/);
|
const matches = origin.trim().match(/^git@github\.com:(.+)\/(.+)\.git$/);
|
||||||
|
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
throw 'Origin is not configured or no ssh url';
|
throw 'Origin is not configured or no ssh url';
|
||||||
|
@ -252,11 +141,10 @@ async function createGithubRelease(changeLog) {
|
||||||
const releaseOptions = {
|
const releaseOptions = {
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
||||||
tag_name: tagName,
|
tag_name: tagName,
|
||||||
name: `BigBlueButton Integration ${tagName}`,
|
name: `BigBlueButton Integration ${tagName}`,
|
||||||
body: changeLog.replace(/^## [^\n]+\n/, ''),
|
body: changeLog.replace(/^## [^\n]+\n/, ''),
|
||||||
prerelease: !/^\d+\.\d+\.\d+$/.test(package.version),
|
prerelease: !/^\d+\.\d+\.\d+$/.test(packageInfo.version),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDryRun) {
|
if (isDryRun) {
|
||||||
|
@ -289,9 +177,8 @@ async function createGithubRelease(changeLog) {
|
||||||
const uploadOptions = {
|
const uploadOptions = {
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
||||||
release_id: releaseResponse.data.id,
|
release_id: releaseResponse.data.id,
|
||||||
data: fs.createReadStream(file),
|
data: <any> fs.createReadStream(file),
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': getMimeType(filename),
|
'content-type': getMimeType(filename),
|
||||||
'content-length': fs.statSync(file)['size'],
|
'content-length': fs.statSync(file)['size'],
|
||||||
|
@ -316,7 +203,7 @@ async function uploadToNextcloudStore(archiveUrl) {
|
||||||
|
|
||||||
const hostname = 'apps.nextcloud.com';
|
const hostname = 'apps.nextcloud.com';
|
||||||
const apiEndpoint = '/api/v1/apps/releases';
|
const apiEndpoint = '/api/v1/apps/releases';
|
||||||
const signatureFile = files.find(file => file.endsWith('.ncsig'));
|
const signatureFile = <string> files.find(file => file.endsWith('.ncsig'));
|
||||||
const data = JSON.stringify({
|
const data = JSON.stringify({
|
||||||
download: archiveUrl,
|
download: archiveUrl,
|
||||||
signature: fs.readFileSync(signatureFile, 'utf-8'),
|
signature: fs.readFileSync(signatureFile, 'utf-8'),
|
||||||
|
@ -339,7 +226,7 @@ async function uploadToNextcloudStore(archiveUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const req = https.request(options, res => {
|
const req = https.request(options, res => {
|
||||||
if (res.statusCode === 200) {
|
if (res.statusCode === 200) {
|
||||||
console.log('App release was updated successfully'.verbose);
|
console.log('App release was updated successfully'.verbose);
|
||||||
|
@ -383,23 +270,16 @@ async function run() {
|
||||||
await isMasterBranch();
|
await isMasterBranch();
|
||||||
console.log('✔ this is the master branch'.green);
|
console.log('✔ this is the master branch'.green);
|
||||||
|
|
||||||
let changeLog = await generateChangelog();
|
await hasChangeLogEntry(packageInfo.version);
|
||||||
console.log('✔ change log generated'.green);
|
console.log('✔ there is a change log entry for this version'.green);
|
||||||
|
|
||||||
changeLog = await editChangeLog(changeLog);
|
const changeLog = await getChangelogEntry(packageInfo.version);
|
||||||
console.log('✔ change log updated'.green);
|
|
||||||
|
|
||||||
console.log(changeLog);
|
console.log(changeLog);
|
||||||
|
|
||||||
console.log('Press any key to continue...');
|
console.log('Press any key to continue...');
|
||||||
await keypress();
|
await keypress();
|
||||||
|
|
||||||
await hasChangeLogEntry();
|
|
||||||
console.log('✔ there is a change log entry for this version'.green);
|
|
||||||
|
|
||||||
await commitChangeLog();
|
|
||||||
console.log('✔ change log commited'.green);
|
|
||||||
|
|
||||||
await hasArchiveAndSignatures();
|
await hasArchiveAndSignatures();
|
||||||
console.log('✔ found archive and signatures'.green);
|
console.log('✔ found archive and signatures'.green);
|
||||||
|
|
||||||
|
@ -430,7 +310,7 @@ async function run() {
|
||||||
|
|
||||||
await uploadToNextcloudStore(archiveAssetUrl);
|
await uploadToNextcloudStore(archiveAssetUrl);
|
||||||
console.log('✔ released in Nextcloud app store'.green);
|
console.log('✔ released in Nextcloud app store'.green);
|
||||||
};
|
}
|
||||||
|
|
||||||
run().catch(err => {
|
run().catch(err => {
|
||||||
console.log(`✘ ${err.toString()}`.error);
|
console.log(`✘ ${err.toString()}`.error);
|
17
yarn.lock
17
yarn.lock
|
@ -1348,6 +1348,14 @@
|
||||||
"@types/jquery" "*"
|
"@types/jquery" "*"
|
||||||
popper.js "^1.14.1"
|
popper.js "^1.14.1"
|
||||||
|
|
||||||
|
"@types/inquirer@^7.3.1":
|
||||||
|
version "7.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d"
|
||||||
|
integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==
|
||||||
|
dependencies:
|
||||||
|
"@types/through" "*"
|
||||||
|
rxjs "^6.4.0"
|
||||||
|
|
||||||
"@types/jquery@*", "@types/jquery@^3.3.35":
|
"@types/jquery@*", "@types/jquery@^3.3.35":
|
||||||
version "3.5.5"
|
version "3.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.5.tgz#2c63f47c9c8d96693d272f5453602afd8338c903"
|
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.5.tgz#2c63f47c9c8d96693d272f5453602afd8338c903"
|
||||||
|
@ -1430,6 +1438,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74"
|
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74"
|
||||||
integrity sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==
|
integrity sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==
|
||||||
|
|
||||||
|
"@types/through@*":
|
||||||
|
version "0.0.30"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
|
||||||
|
integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/uglify-js@*":
|
"@types/uglify-js@*":
|
||||||
version "3.11.1"
|
version "3.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.11.1.tgz#97ff30e61a0aa6876c270b5f538737e2d6ab8ceb"
|
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.11.1.tgz#97ff30e61a0aa6876c270b5f538737e2d6ab8ceb"
|
||||||
|
@ -7100,7 +7115,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
aproba "^1.1.1"
|
aproba "^1.1.1"
|
||||||
|
|
||||||
rxjs@^6.6.0:
|
rxjs@^6.4.0, rxjs@^6.6.0:
|
||||||
version "6.6.3"
|
version "6.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
|
||||||
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
|
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
|
||||||
|
|
Loading…
Reference in New Issue