Continuous integration for chrome extension using web store API

1,435 views
Skip to first unread message

Vivek Bolajwar

unread,
Oct 2, 2015, 1:33:42 PM10/2/15
to Chromium-extensions
Hi,

Has anyone tried implementing a continuous integration for Chrome extension?

I am currently using Jenkins to build the extension but can not find a way to automate the publishing process.

I have also noticed there is Web Store API but that too needs human intervention to get access token.

Thanks in advance,
Vivek

Paul Draper

unread,
Oct 2, 2015, 1:54:27 PM10/2/15
to Vivek Bolajwar, Chromium-extensions
I have done this.

The OAuth 2.0 refresh token does not expire.
So you can get it once and continue to use it.

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/ab586314-fdf5-4ca5-a79d-1ca25a02fced%40chromium.org.
For more options, visit https://groups.google.com/a/chromium.org/d/optout.

Vivek Bolajwar

unread,
Oct 2, 2015, 2:00:36 PM10/2/15
to Chromium-extensions, ukdv...@gmail.com
Thats great Paul!

But what about the access code that you are supposed to get? Docs say it will expire every 10 minutes. Would that be one time for refresh token?

If I understand correctly this is what I should do.

1. Create credentials
2. Get the access code by putting a URL in browser and 'allow' the access
3. Request for refresh token using client id and access code
4. Use the refresh token every time I need to upload extension zip and use publish API similarly.

Please correct me if I have missed anything.

Thanks,
Vivek


On Friday, October 2, 2015 at 1:54:27 PM UTC-4, Paul Draper wrote:
I have done this.

The OAuth 2.0 refresh token does not expire.
So you can get it once and continue to use it.
On Fri, Oct 2, 2015 at 11:33 AM, Vivek Bolajwar <ukdv...@gmail.com> wrote:
Hi,

Has anyone tried implementing a continuous integration for Chrome extension?

I am currently using Jenkins to build the extension but can not find a way to automate the publishing process.

I have also noticed there is Web Store API but that too needs human intervention to get access token.

Thanks in advance,
Vivek

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extensions+unsub...@chromium.org.

Paul Draper

unread,
Oct 2, 2015, 2:09:46 PM10/2/15
to Vivek Bolajwar, Chromium-extensions
It helps if you know the basics of OAuth 2, and Google API stuff.

You are basically granting the ability for an application (e.g. Jenkins) to perform certain actions on your behalf.

Create a Google API project and get your client id and secret. These are the same for any Google user that your application has access to. (Though in this case, it's probably just one user.)

Then get a user-specific refresh token through your browser. The client id, secret, and refresh token don't change, unless you revoke something.
Those three can be used to get a temporary access token as often as you like (subject to some API limitation).

The access token is used on all requests, usually in the Authorization header (Bearer abc123).

This is a Python script that is a part of my deploy:

from __future__ import print_function
import json
import requests
import subprocess
import sys
from termcolor import colored, cprint
from zipfile import ZipFile

def publish(package, app_id, client_id, client_secret, refresh_token, visibility):
    def check_response_success(response):
        if response.status_code != 200:
            cprint('Status {} {}'.format(response.status_code, response.reason), 'red')
            print(response.text)
            sys.exit(1)

        'client_id': client_id,
        'client_secret': client_secret,
        'grant_type': 'refresh_token',
        'refresh_token': refresh_token,
    })
    check_response_success(response)
    access_token = response.json()['access_token']

    session = requests.Session()
    session.headers['Authorization'] = 'Bearer {}'.format(access_token)

    cprint('Getting details for {}'.format(app_id), 'cyan')
    # currently, only DRAFT is supported
    response = session.get(url)
    check_response_success(response)
    data = response.json()
    if data.get('itemError'):
        for error in data['itemError']:
            cprint('{}: {}'.format(error['error_code'], error['error_detail']), 'red')
        sys.exit(1)
    current_version = data['crxVersion']
    print('Current Webstore version is {}'.format(current_version))

    with ZipFile(package, 'r') as f:
        manifest_name = next(name for name in f.namelist() if name.endswith('manifest.json'))
        manifest = json.load(f.open(manifest_name))
        print('Found {} with version {}'.format(manifest_name, manifest['version']))
    version_parts = current_version.split('.')
    major_version = version_parts[0]
    minor_version = version_parts[1] if len(version_parts) > 1 else '0'
    new_version = '.'.join((major_version, str(int(minor_version) + 1)))
    print('Setting {} to version {}'.format(manifest_name, new_version))
    manifest['version'] = new_version
    subprocess.check_call(['zip', '-d', package, manifest_name], stdout=subprocess.PIPE)
    with ZipFile(package, 'a') as f:
        f.writestr(manifest_name, json.dumps(manifest, indent=4))

    cprint('Uploading {}'.format(package), 'cyan')
    with open(package, 'r') as f:
        def print_progress():
            progress = 0
            for line in f:
                progress += len(line)
                print('{:.2f} MB'.format(progress / 1024. / 1024.), end='\r')
                sys.stdout.flush()
                yield line
        response = session.put(url, data=print_progress())
        print()
    check_response_success(response)
    data = response.json()
    if data.get('itemError'):
        for error in data['itemError']:
            cprint('{}: {}'.format(error['error_code'], error['error_detail']), 'red')
        sys.exit(1)
    cprint(data['uploadState'], 'green')

    cprint('Publishing {}'.format(app_id), 'cyan')
    response = session.post(url, data='')
    check_response_success(response)
    data = response.json()
    cprint(data['status'][0], 'green' if data['status'][0] == 'OK' else 'red')

I should probably put together a little open-source project to do this :)

If memory serves, AdBlock has an open-source deploy too.

On Fri, Oct 2, 2015 at 12:00 PM, Vivek Bolajwar <ukdv...@gmail.com> wrote:
Thats great Paul!

But what about the access code that you are supposed to get? Docs say it will expire every 10 minutes. Would that be one time for refresh token?

If I understand correctly this is what I should do.

1. Create credentials
2. Get the access code by putting a URL in browser and 'allow' the access
3. Request for refresh token using client id and access code
4. Use the refresh token every time I need to upload extension zip and use publish API similarly.

Please correct me if I have missed anything.

Thanks,
Vivek

On Friday, October 2, 2015 at 1:54:27 PM UTC-4, Paul Draper wrote:
I have done this.

The OAuth 2.0 refresh token does not expire.
So you can get it once and continue to use it.
On Fri, Oct 2, 2015 at 11:33 AM, Vivek Bolajwar <ukdv...@gmail.com> wrote:
Hi,

Has anyone tried implementing a continuous integration for Chrome extension?

I am currently using Jenkins to build the extension but can not find a way to automate the publishing process.

I have also noticed there is Web Store API but that too needs human intervention to get access token.

Thanks in advance,
Vivek

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.

To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.

Vivek Bolajwar

unread,
Oct 2, 2015, 2:35:22 PM10/2/15
to Chromium-extensions, ukdv...@gmail.com
This is really useful Paul!

Appreciate your help! I think its worth a repository or atleast a blog post :-)

Big Thanks,
Vivek
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extensions+unsub...@chromium.org.

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extensions+unsub...@chromium.org.

To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.

Vivek Bolajwar

unread,
Oct 2, 2015, 3:37:48 PM10/2/15
to Chromium-extensions
I was able to setup automated publishing from Jenkins build server using grunt task.

Many thanks to Paul for quick turnaround.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extensions+unsub...@chromium.org.

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extensions+unsub...@chromium.org.

To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.

Rob Garrison

unread,
Oct 9, 2015, 8:02:23 PM10/9/15
to Chromium-extensions
Hey Vivek! Can you please share how you implemented a build using grunt?

Vivek Bolajwar

unread,
Oct 10, 2015, 9:47:43 PM10/10/15
to Rob Garrison, Chromium-extensions
Hi Rob,

I assume you already have client id, client secret and refresh token at hand.

I am using Docker image of Jenkins and installed NodeJS and grunt-cli on that instance.

I am also using grunt-webstore-publish task I have found on GitHub  https://github.com/c301/grunt-webstore-upload

As explained in one of the configuration examples, I am passing OAuth refresh token in the grunt configuration for publishing the extension.

Let me know if you need more information about how my grunt configuration looks like.

Thanks,
Vivek

On Fri, Oct 9, 2015 at 8:02 PM, Rob Garrison <wowm...@gmail.com> wrote:
Hey Vivek! Can you please share how you implemented a build using grunt?

--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.

To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.

Rob Garrison

unread,
Oct 11, 2015, 8:56:01 AM10/11/15
to Chromium-extensions, wowm...@gmail.com
Thanks Vivek!

I didn't think to look for a grunt task, that does help a lot.

Thanks much! I appreciate the quick response and the info.
Rob

Ricardo Feliciano

unread,
Oct 23, 2017, 4:48:11 PM10/23/17
to Chromium-Extensions-Announce
Hey everyone, I'm bumping an old thread (sorry) only because I think this is actually useful. Not too long ago I had these same CI questions and found this thread and a Stack Overflow question on this topic. There was information trickling in but not one complete resource.

So, I wrote a blog post on Chrome Extensions and CI here. The blog post is CircleCI specific but much of the information can apply to similar CI SaaS services if you use something similar.

clouduan

unread,
Jul 31, 2018, 8:33:32 AM7/31/18
to Chromium-Extensions-Announce
Thanks man, I've just read that post. It's excellent!

在 2017年10月24日星期二 UTC+8上午4:48:11,Ricardo Feliciano写道:
Reply all
Reply to author
Forward
0 new messages