Goals

Promote repositories to 0.1.x · Issue #24 · gitenberg-dev/Second-Folio

Our process for generating epub for almost all of the Second Folio books is good enough to now promote version to 0.1.x. Specifically:

  • mark version in metadata.yaml to 0.1.0 (or 0.1.x)
  • include the GITenberg keyword
  • add a webhook notification to https://unglue.it/api/travisci/webhook in each .travis.yml so the repos get loaded to unglue.it

In [ ]:
from __future__ import print_function

import json
import yaml
from itertools import (islice, izip)

import arrow
from gitenberg import metadata
import jinja2
import semantic_version


import requests
from second_folio import (all_repos, 
                          apply_to_repos, 
                          git_pull,
                          travis_template,
                          repo_version,
                          travis_template,
                          slugify,
                          TRAVIS_TEMPLATE_URL
                          )

from github_settings import (username, password, token)

# import github3.py
import github3

GITenberg_ORG = "GITenberg"

# https://github.com/sigmavirus24/github3.py/pull/368/files
# for personal access tokens
gh = github3.login(username, password=token)

In [ ]:
repos = list(islice(all_repos,0,None))
repos

In [ ]:
# git pull to get updated 

results = list(izip(repos, apply_to_repos(git_pull,
                                        repos=repos)))
[result for result in results if isinstance(result[1], Exception) ]

In [ ]:
# which books still at 0.0.1

[(repo, version_info) for (repo, version_info) in 
   izip(repos, apply_to_repos(repo_version, repos=repos, kwargs={'version_type':'minor', 'write_version':False}))
   if version_info[0] == '0.0.1']

In [ ]:
# loop over repos and see which ones need to be updated to 0.1.0

list(apply_to_repos(repo_version, repos=repos, kwargs={'version_type':'minor', 'write_version':False}))

Using github3.py to make changes


In [ ]:
gh = github3.login(username, password=token)
gh.user().name, gh.user().email

Different ways to work with .travis.yml:

  • use the template
  • manipulate directly as a yaml file

In [ ]:
# rewrite function without assuming that there is a local copy of the repo


class GITenbergPromoter(object):
    def __init__(self, username, token, repo_name, owner_name='GITenberg',
               update_travis_commit_msg = "updated .travis.yml",
               promote_commit_message = "promote to 0.1.x; add GITenberg keyword",
               keywords=('GITenberg',)):
        
        self.gh = github3.login(username, password=token)
        self.repo = self.gh.repository(owner_name, repo_name)
        self.repo_name = repo_name
        self.owner_name = owner_name
        self.update_travis_commit_msg = update_travis_commit_msg
        self.promote_commit_message = promote_commit_message
        self.keywords = keywords
        
    def promote(self, write_changes=True, update_travis=True, promote_repo=True):
        if update_travis:
            (template_result, template_written, commit) =  self.update_travis_template(write_changes=write_changes)
        else:
            (template_result, template_written, commit)  = (None, None, None)
        
        if promote_repo:
            (_version, _next_version, metadata_updated, commit, tag) = self.promote_repo_to_minor_add_kw(write_changes=write_changes)
        else:
            (_version, _next_version, metadata_updated, commit, tag) = (None, None, None, None, None)
        
        return [(template_result, template_written, commit),
               (_version, _next_version, metadata_updated, commit, tag)]
        
    def metadata(self):
        """
        returns a metadata.pandata.Pandata object for repo
        """
        metadata_url = "https://raw.githubusercontent.com/{owner}/{repo_name}/master/metadata.yaml".format(owner=self.owner_name,
                                                                               repo_name=self.repo_name)

        md = metadata.pandata.Pandata(metadata_url)
        return md

        
    def update_travis_template(self, write_changes=True, template=None):
        """
        compute (and optionally write) .travis.yml based on the template and current metadata.yaml 

        repo: github3.py representation of repository
        """
        template_written = False

        if template is None:
            template = travis_template()
        
        md = self.metadata()
        repo_name = md.metadata.get("_repo")
        epub_title = slugify(md.metadata.get("title"))

        # pick from rep
        encrypted_key = self.repo.contents(".travis.deploy.api_key.txt", ref='master').decoded.decode('utf-8')

        template_vars =  {
            'epub_title': epub_title,
            'encrypted_key': encrypted_key,
            'repo_name': repo_name
        }

        template_result = template.render(**template_vars)

        if write_changes:
            # how to write to file 
            content = self.repo.contents('.travis.yml', ref='master')
            data = {
                'message': self.update_travis_commit_msg,
                'content': template_result.encode('utf-8'),
            }

            commit = content.update(**data)
        else:
            commit = None

        return (template_result, template_written, commit)
    def promote_repo_to_minor_add_kw(self, write_changes=True):
        """
        github3.py representation of repository
        returns current version, next version, whether metadata updated, commit
        """

        md = self.metadata()

        # promote to 0.1.0 or next patch if current version is at least a minor version

        _version = semantic_version.Version(md.metadata.get("_version"))
        if _version >= semantic_version.Version("0.1.0"):
            _next_version = unicode(_version.next_patch())
        else:
             _next_version = u"0.1.0"

        # add keywords 
        subjects = md.metadata.get("subjects")
        for keyword in self.keywords:
            if keyword not in subjects:
                subjects.append(keyword)
        md.metadata["subjects"] = subjects

        if write_changes:

            # how to write to file 
            content = self.repo.contents('metadata.yaml', ref='master')
            md.metadata["_version"] =  _next_version
            data = {
                'message': self.promote_commit_message,
                'content': yaml.safe_dump(md.metadata,default_flow_style=False,allow_unicode=True)
            }
            commit = content.update(**data)

            # also tag the commit
            tag_data =  {
                'tag': _next_version,
                'message': _next_version,
                'sha': commit.sha,
                'obj_type': 'commit',
                'tagger': {
                    'name': self.gh.user().name,
                    'email': gh.user().email,
                    'date': arrow.utcnow().isoformat()
                },
                'lightweight': False
            }

            tag = self.repo.create_tag(**tag_data)

            metadata_updated = True
        else:
            commit = None
            tag = None
            metadata_updated = False

        return (_version, _next_version, metadata_updated, commit, tag)
    
    def url_latest_epub(self):
        """
        repo is a github3.py repo
        """
        
        md = self.metadata()
        epub_title = slugify(md.metadata.get("title"))
        tag = md.metadata.get("_version")
        url = "https://github.com/GITenberg/{}/releases/download/{}/{}.epub".format(self.repo_name, tag, epub_title)
        return url
    
    def status_latest_epub(self):
        return requests.head(self.url_latest_epub()).status_code

In [ ]:
def promote_repo(repo_name):
    gp = GITenbergPromoter(username, token, repo_name)
    try:
        result = gp.promote(write_changes=True, update_travis=True, promote_repo=True)
    except Exception as e:
        result = e
    return (result, gp)
    
def epub_status(repo_name):
    gp = GITenbergPromoter(username, token, repo_name)
    return gp.status_latest_epub()

In [ ]:
repos = all_repos

for (repo, status) in izip(repos, apply_to_repos(epub_status, repos=repos)):
    print (repo, status)

In [ ]:
all_repos[7:10]

In [ ]:
results = list(apply_to_repos(promote_repo, repos=all_repos[10:]))
list(results)

In [ ]:
gp = results[0][-1]
gp.status_latest_epub()

In [ ]:
gp = GITenbergPromoter(username, token, repo_name)
gp.status_latest_epub()

In [ ]:
(template_result, template_written, commit) = new_travis_template_2(repo=repo, template=template, write_template=True)
(template_result, template_written, commit)

In [ ]:
(template_result, template_written, commit)

update metadata.yml


In [ ]:
def repo_version_2(repo, version_type='patch', write_version=False):
    """
    github3.py representation of repository
    returns current version, next version, whether metadata updated, commit
    """
    
    assert version_type in ('patch', 'minor', 'major')
    
    metadata_updated = False
    metadata_url = "https://raw.githubusercontent.com/{owner}/{repo_name}/master/metadata.yaml".format(owner='GITenberg',
                                                                            repo_name=repo.name)

    md = metadata.pandata.Pandata(metadata_url)
    
    _version = md.metadata.get("_version")
    next_func = getattr(semantic_version.Version(_version), "next_{}".format(version_type))
    _next_version = unicode(next_func())

    if write_version:
        
        # how to write to file 
        content = repo.contents('metadata.yaml', ref='master')
        md.metadata["_version"] =  _next_version
        data = {
            'message': 'updated metadata.yaml',
            'content': yaml.safe_dump(md.metadata,default_flow_style=False,allow_unicode=True)
        }
        commit = content.update(**data)
        metadata_updated = True
    else:
        commit = None

    return (_version, _next_version, metadata_updated, commit)

In [ ]:
import arrow

def promote_repo_to_minor_add_kw(repo, user_name, user_email, commit_message,
                                 keywords=('GITenberg',), write_version=False):
    """
    github3.py representation of repository
    returns current version, next version, whether metadata updated, commit
    """
        
    metadata_updated = False
    metadata_url = "https://raw.githubusercontent.com/{owner}/{repo_name}/master/metadata.yaml".format(owner='GITenberg',
                                                                            repo_name=repo.name)

    md = metadata.pandata.Pandata(metadata_url)
    
    # promote to 0.1.0 or next patch if current version is at least a minor version
    
71    _version = semantic_version.Version(md.metadata.get("_version"))
    if _version >= semantic_version.Version("0.1.0"):
        _next_version = unicode(_version.next_patch())
    else:
         _next_version = u"0.1.0"
            
    # add keywords 
    subjects = md.metadata.get("subjects")
    for keyword in keywords:
        if keyword not in subjects:
            subjects.append(keyword)
    md.metadata["subjects"] = subjects
            
    if write_version:
        
        # how to write to file 
        content = repo.contents('metadata.yaml', ref='master')
        md.metadata["_version"] =  _next_version
        data = {
            'message': commit_message,
            'content': yaml.safe_dump(md.metadata,default_flow_style=False,allow_unicode=True)
        }
        commit = content.update(**data)
        
        # also tag the commit
        tag_data =  {
            'tag': _next_version,
            'message': _next_version,
            'sha': commit.sha,
            'obj_type': 'commit',
            'tagger': {
                'name': user_name,
                'email': user_email,
                'date': arrow.utcnow().isoformat()
            },
            'lightweight': False
        }

        tag = repo.create_tag(**tag_data)
        
        metadata_updated = True
    else:
        commit = None
        tag = None

    return (_version, _next_version, metadata_updated, commit, tag)

In [ ]:
user = gh.user()


(_version, _next_version, metadata_updated, commit, tag) = promote_repo_to_minor_add_kw(repo=repo,
                                                                user_name=user.name, 
                                                                user_email=user.email,
                                                                write_version=False,
                                                                commit_message="promote to 0.1.x; add GITenberg keyword")
(_version, _next_version, metadata_updated, commit, tag)

In [ ]:
def latest_epub_2(repo):
    """
    repo is a github3.py repo
    """
    metadata_url = "https://raw.githubusercontent.com/{owner}/{repo_name}/master/metadata.yaml".format(owner='GITenberg',
                                                                            repo_name=repo.name)

    md = metadata.pandata.Pandata(metadata_url)
    #repo_name = md.metadata.get("_repo")
    epub_title = slugify(md.metadata.get("title"))
    tag = md.metadata.get("_version")
    url = "https://github.com/GITenberg/{}/releases/download/{}/{}.epub".format(repo, tag, epub_title)
    return url

In [ ]:
import requests
requests.head(latest_epub_2(repo)).status_code