git | update git | ,git project directory | Search

This code automates Git repository and build workflows using calendar events, triggering builds and tests while also updating existing events with the latest commit information.

Run example

npm run import -- "github updates"

github updates

var _ = require('lodash');
var {JSDOM} = require('jsdom');
var importer = require('../Core');
var {
    gitTree, execCmd, getOauthClient, createNewEvent,
    updateEvent, cloneProject, getDaysEvents
} = importer.import("d3.ipynb[format d3 tree]",
"json git tree",
"spawn child process",
"import google calendar api",
"create merge delete event",
"git project directory",
"days events",
"create new calendar event");

var options = {
    calendarId: 'aws'
}

// create a calendar event to retest this branch
function installBuildTestEvent(project) {
    return createNewEvent('spawn child process', JSON.stringify({
        script: `npm install\nnpm run build\nnpm run test`,
        options: {cwd: project} // TODO: fix current working directory using project name?
    }, null, 4), options)
}

function updateHeartbeatEvent(project, branch, commit) {
    return getOauthClient(options)
        .then(() => getDaysEvents(new Date(), options))
        .then(r => {
            const heartbeat = r.filter(r => r.event.summary === 'heartbeat'
                                       || r.event.summary === 'todays heartbeat items');
            try {
                var dom = new JSDOM('<body>' + (heartbeat[0].event.description || '').replace(/<br\/?>/igm, '\n') + '</body>');
                const desc = dom.window.document.body.textContent.split('\n');
                desc.forEach((c, i) => {
                    if(c.trim().length > 0 && c.includes('github updates')) {
                        const parameters = JSON.parse(((/[\{].*[\}]|[\[].*[\]]|(['"]).*\1/igm).exec(c) || ['""'])[0]);
                        if(parameters[0] === project && parameters[1] === branch) {
                            parameters[2] = commit;
                        }
                        desc[i] = 'github updates ' + JSON.stringify(parameters);
                    }
                });
                assert(desc.length, 'there is a serious problem with updating the commit');
                heartbeat[0].event.description = desc.join('\n');
                return updateEvent(heartbeat[0].event, options);
            } catch ( e ) {
                console.log(e);
            }
        })
}

function findBranchRemote(project, branch) {
    return execCmd(`git branch -r`, {cwd: project}) // 
        .then(r => {
            const remotes = r.join('\n').split(/\s*\n\s*/igm).filter(r => (r.split('/')[1] || '').trim() === branch);
            if(remotes.length === 0) {
                throw new Error('branch "' + branch + '" not found on any remotes ' + JSON.stringify(r))
            }
            remote = remotes[0].split('/')[0];
            return remote;
        })
        .then(() => ({remote, branch}))
}

function getUpdate(project, branch, fromCommit) {
    var projectCopy, latestCommit;
    return cloneProject(project)
        .then(p => {
            projectCopy = p;
            return findBranchRemote(projectCopy, branch);
        })
        .then(({remote, branch}) => execCmd(`
git fetch ${remote}
git log ${fromCommit || 'HEAD'}..${remote}/${branch}`, {cwd: projectCopy}))
        .then(log => {
            if(log.join('').trim().length > 0) {
                latestCommit = (/commit (.*)/ig).exec(log.join(''))[1];
                return cloneProject(projectCopy, true)
            } else {
                throw new Error('nothing for git to do');
            }
        })
        .then(r => {
            projectCopy = r;
            if(branch) {
                return execCmd(`
git reset --hard
git checkout ${branch}`, {cwd: projectCopy})
            }
        })
        .then(() => execCmd(importer.interpret('git auto rebase').code.trim()
                            + ` ${remote} ${branch}`, {cwd: projectCopy}))
        .then(() => installBuildTestEvent(projectCopy))
    // TODO: update heartbeat event description to pass in the latest commit
        .then(() => updateHeartbeatEvent(project, branch, latestCommit))
}
module.exports = getUpdate;

// git log currentbranch@{1}..currentbranch
// where the @{1} notation means "the commit the branch pointed to just before it last got updated".
// git log HEAD..swiftpage/development

if(typeof $ !== 'undefined') {
    $.async();
    getUpdate('portal')
        .then(r => $.sendResult(r))
        .catch(e => $.sendError(e))
}

What the code could have been:

const { JSDOM } = require('jsdom');
const importer = require('../Core');
const {
    gitTree, execCmd, getOauthClient, createNewEvent, updateEvent, cloneProject,
    getDaysEvents, interpret, spawnChildProcess
} = importer.import([
    'd3.ipynb[format d3 tree]',
    'json git tree',
   'spawn child process',
    'import google calendar api',
    'create merge delete event',
    'git project directory',
    'days events',
    'create new calendar event'
]);

class UpdateManager {
    constructor(calendarId) {
        this.calendarId = calendarId;
    }

    async createCalendarEvent(project, script) {
        return createNewEvent('spawn child process', JSON.stringify({
            script,
            options: { cwd: project }
        }), { calendarId: this.calendarId })
    }

    async updateHeartbeatEvent(project, branch, commit) {
        try {
            const client = await getOauthClient({ calendarId: this.calendarId });
            const events = await getDaysEvents(new Date(), { calendarId: this.calendarId });
            const heartbeat = events.filter(event => event.summary === 'heartbeat' || event.summary === 'todays heartbeat items');

            if (!heartbeat.length) {
                throw new Error('No heartbeat events found');
            }

            const dom = new JSDOM(`${(heartbeat[0].event.description || '').replace(//igm, '\n')}');
            const description = dom.window.document.body.textContent.split('\n');

            description.forEach((line, index) => {
                if (line.trim().length > 0 && line.includes('github updates')) {
                    const parameters = JSON.parse(((/[\{].*[\}]|[\[].*[\]]|(['"]).*\1/igm).exec(line) || ['""'])[0]);
                    if (parameters[0] === project && parameters[1] === branch) {
                        parameters[2] = commit;
                    }
                    description[index] = `github updates ${JSON.stringify(parameters)}`;
                }
            });

            heartbeat[0].event.description = description.join('\n');
            return updateEvent(heartbeat[0].event, { calendarId: this.calendarId });
        } catch (error) {
            console.log(error);
        }
    }

    async findBranchRemote(project, branch) {
        const remote = await execCmd('git branch -r', { cwd: project });
        const remotes = remote.join('\n').split(/\s*\n\s*/igm).filter(remote => (remote.split('/')[1] || '').trim() === branch);

        if (!remotes.length) {
            throw new Error(`Branch "${branch}" not found on any remotes: ${remote.join('\n')}`);
        }

        return { remote: remotes[0].split('/')[0], branch };
    }

    async getUpdate(project, branch, fromCommit) {
        const projectCopy = await cloneProject(project);
        const { remote, branch: localBranch } = await this.findBranchRemote(projectCopy, branch);

        const log = await execCmd(`git fetch ${remote} && git log ${fromCommit || 'HEAD'}..${remote}/${localBranch}`, { cwd: projectCopy });
        const latestCommit = log.join('').trim().length > 0? (/commit (.*)/ig).exec(log.join(''))[1] : null;

        if (!latestCommit) {
            throw new Error('No updates to apply');
        }

        await execCmd('git reset --hard && git checkout'+ localBranch, { cwd: projectCopy });
        await execCmd(importer.interpret('git auto rebase').code.trim() + ` ${remote} ${localBranch}`, { cwd: projectCopy });
        await this.createCalendarEvent(projectCopy, `npm install && npm run build && npm run test`);
        await this.updateHeartbeatEvent(project, localBranch, latestCommit);

        return projectCopy;
    }
}

module.exports = (calendarId) => {
    return new UpdateManager(calendarId);
}

if (typeof $!== 'undefined') {
    $.async();
    new UpdateManager('aws')
       .getUpdate('portal')
       .then(result => $.sendResult(result))
       .catch(error => $.sendError(error));
}

This code snippet focuses on managing and updating calendar events related to Git repositories and builds.

Here's a breakdown:

  1. Imports:

  2. Calendar Event Configuration:

  3. installBuildTestEvent Function:

  4. updateHeartbeatEvent Function:

Key Concepts:

In essence, this code snippet demonstrates how to use calendar events to manage and automate workflows involving Git repositories, builds, and testing.