如何使用脚本在GitHub上发布构建工件资产?

时间:2011-03-05 22:37:50

标签: github

我试图弄清楚在GitHub上生成构建的单命令过程。

我期望做的是运行某种命令发布,比如说,make release脚本构建了发布工件,然后以某种方式将其上传到GitHub。

但是,我对如何在GitHub上实际获取发布工件感到困惑。源代码很棒,但不是每个人都想做自己的构建。 :-)

8 个答案:

答案 0 :(得分:18)

Update September 2013,您可以自动发布API in preview mode

Update January 2014github-release有一个名为 Nicolas Hillegeer (aktau) 的非官方命令行应用,用于创建发布和上传(二进制)工件。
> 它使用上面提到的新github发布API。查看项目的Makefile,了解如何更自动化它。

示例:

# create a formal release
$ github-release release \
    --user aktau \
    --repo gofinance \
    --tag v0.1.0 \
    --name "the wolf of source street" \
    --description "Not a movie, contrary to popular opinion. Still, my first release!" \
    --pre-release

  

由于二进制资产,此API略有不同。我们在请求发布资产时使用Accept标头进行内容协商   传递标准API媒体类型以获取API表示:

$ curl -i -H "Authorization: token TOKEN" \
     -H "Accept: application/vnd.github.manifold-preview" \
     "https://uploads.github.com/repos/hubot/singularity/releases/assets/123"

HTTP/1.1 200 OK

{
  "id": 123,
...
}
  

传递“application / octet-stream”以下载二进制内容。

$ curl -i -H "Authorization: token TOKEN" \
     -H "Accept: application/octet-stream" \
     "https://uploads.github.com/repos/hubot/singularity/releases/assets/123"

HTTP/1.1 302 Found
  

上传由对协作“uploads.github.com”服务的单个请求处理。

$ curl -H "Authorization: token TOKEN" \
     -H "Accept: application/vnd.github.manifold-preview" \
     -H "Content-Type: application/zip" \
     --data-binary @build/mac/package.zip \
     "https://uploads.github.com/repos/hubot/singularity/releases/123/assets?name=1.0.0-mac.zip"

Update 2d July 2013,您现在可以定义发布

release

  • 发布时附有发行说明和下载软件或源代码的链接。
  • 遵循许多Git项目的惯例,版本与Git标签相关联。您可以使用现有标记,也可以在发布标记时创建标记。
  • 您还可以将二进制资产(例如已编译的可执行文件,缩小的脚本,文档)附加到发布。发布后,任何可以查看存储库的人都可以使用发布详细信息和资产。

这就是替换old binary upload serviceremoved in December 2012


  

make release脚本构建了发布工件,然后以某种方式将其上传到github。

这意味着将它(“它”是由一个或多个文件(通常包括二进制文件)组成的传递添加到常规本地存储库,然后将该存储库推送到其匹配的GitHub存储库。

话虽如此,GitHub在任何“发布”任务中都没有提到的原因是因为Git是一个控制管理系统,并且不适合二进制文件。

它当然可以包含那些文件(二进制文件),但不会定期使用它们,因为一段时间后回购的大小膨胀:每次克隆需要更长时间。 请参阅What are the Git limits,以及“git - should source files and repository be on the same machine ?”。

答案 1 :(得分:8)

的制备:将

1)下载github-releases并将其可执行文件放入PATH中 2)在https://github.com/settings/applications#personal-access-tokens创建一个令牌,让我们说abc123

上传工件:

1)假设您刚刚编译了您决定调用版本3.1的内容,并希望上传它 2)确保你已经兑现了一切 3)运行以下五个命令:

git tag v3.1
git push
git push --tags

github-release release --security-token abc123 --user <you> --repo <yourrepo> \
    --tag v3.1

github-release upload --security-token abc123 --user <you> --repo <yourrepo> \
    --tag v3.1 --name <thefile> --file <thefile>

您可以上传多个文件,例如用于不同的操作系统。

(基于VonC的回答,遗憾的是没有详细说明如何上传工件)

答案 2 :(得分:2)

如果你使用Maven,你可以添加GitHub的下载Maven插件(https://github.com/github/maven-plugins/#downloads-plugin)并简单地执行:

$ mvn clean install ghDownloads:upload

答案 3 :(得分:1)

Github有一个API来访问他们自己的文件下载系统。 回购下载允许您为用户提供二进制文件 - 尽管可能存在大小和数量的限制。 API允许从自动代理访问。 看一眼: http://developer.github.com/v3/repos/downloads/了解使用信息。

该功能使用不多,但绝对有效。您可以访问任何github仓库,单击“下载”选项卡查看它们。

有关可下载文件的示例: http://github.com/dannystaple/emacs_cheat_sheets/downloads - 提供的HTML文件实际上是一个构建的人工制品,而不是源代码。我试图提出一个更好的(二进制)示例 - 但没有理由不能提供可执行文件,zips / tarball和其他文件类型。

这些下载与repo或其标记的源代码压缩包不同。任何文件都可以通过这种方式上传。

答案 4 :(得分:1)

我遇到了同样的问题,为我做了一个小蟒蛇。我必须说这是一种痛苦,s3是一场彻头彻尾的狂欢。

https://raw.github.com/reklis/utilityscripts/master/github-upload

#!/opt/local/bin/python2.7


import json
import requests
import sys
import argparse
import os
import mimetypes
import pycurl
import cStringIO
from xml.dom import minidom

github_api_root = "https://api.github.com/"

def parse_args():
    parser = argparse.ArgumentParser(description='post a file to github as a download')
    parser.add_argument('--user', dest='user', help='github username', required=True)
    parser.add_argument('--pass', dest='password', help='github password', required=True)
    parser.add_argument('--repo', dest='repo', help='the name of the github repo', required=True)
    parser.add_argument('--file', dest='filepath', help='path of the local file to upload', required=True)
    parser.add_argument('--desc', dest='description', help='descriptive text about this file', required=True)
    parser.add_argument('--owner', dest='owner', help='owner of the github repository', required=True)
    args = parser.parse_args()
    # print args
    return args

def make_dl_post_url(owner, repo):
    url = "%srepos/%s/%s/downloads" % (str(github_api_root), str(owner), str(repo))
    # print url
    return url

def make_dl_delete_url(owner, repo, dlid):
    url = "%srepos/%s/%s/downloads/%s" % (str(github_api_root), str(owner), str(repo), str(dlid))
    # print url
    return url

def add_github_reference(args):
    dl_post_url = make_dl_post_url(args.owner, args.repo)

    fp = args.filepath
    filename = os.path.basename(fp)
    filesize = os.path.getsize(fp)

    mtype, mdetails = mimetypes.guess_type(fp)

    file_description = {
        'name': filename,
        'size': filesize,
        'description': args.description,
        'content_type': mtype
    }
    # print json.dumps(file_description, indent=2)

    github = requests.post(dl_post_url, auth=(args.user, args.password), data=json.dumps(file_description))
    resp = github.json
    # print json.dumps(resp, indent=2)
    return resp

def remove_github_reference(args, dlid):
    dl_delete_url = make_dl_delete_url(args.owner, args.repo, dlid)

    github = requests.delete(dl_delete_url, auth=(args.user, args.password))
    delete_ok = (204 == github.status_code)
    return delete_ok

def post_file_to_s3(file_path, gh):
    # s3 is very particular with field ordering

    # curl \
    # -F "key=downloads/octocat/Hello-World/new_file.jpg" \
    # -F "acl=public-read" \
    # -F "success_action_status=201" \
    # -F "Filename=new_file.jpg" \
    # -F "AWSAccessKeyId=1ABCDEF..." \
    # -F "Policy=ewogIC..." \
    # -F "Signature=mwnF..." \
    # -F "Content-Type=image/jpeg" \
    # -F "file=@new_file.jpg" \
    # https://github.s3.amazonaws.com/

    s3_ok = 201
    xml_buffer = cStringIO.StringIO()

    try:
        post_fields = [
            ('key', str(gh['path'])),
            ('acl', str(gh['acl'])),
            ('success_action_status', str(s3_ok)),
            ('Filename', str(gh['name'])),
            ('AWSAccessKeyId', str(gh['accesskeyid'])),
            ('Policy', str(gh['policy'])),
            ('Signature', str(gh['signature'])),
            ('Content-Type', str(gh['mime_type'])),
          ('file', (pycurl.FORM_FILE, file_path))
        ]
        # print post_fields

        s3 = pycurl.Curl()
        s3.setopt(pycurl.SSL_VERIFYPEER, 0)   
        s3.setopt(pycurl.SSL_VERIFYHOST, 0)
        s3.setopt(pycurl.POST, 1)
        s3.setopt(pycurl.URL, str(gh['s3_url']))
        s3.setopt(pycurl.HTTPPOST, post_fields)
        # s3.setopt(pycurl.VERBOSE, 1)

        # accumulate string response
        s3.setopt(pycurl.WRITEFUNCTION, xml_buffer.write)

        s3.perform()

        file_upload_success = (s3_ok == s3.getinfo(pycurl.HTTP_CODE))
        xml_payload = minidom.parseString(xml_buffer.getvalue())

        if (file_upload_success):
            location_element = xml_payload.getElementsByTagName('Location')
            print location_element[0].firstChild.nodeValue
        else:
            print xml_payload.toprettyxml()


    except Exception, e:
        print e
        file_upload_success = False

    finally:
        s3.close()

    return file_upload_success


def main():
    mimetypes.init()
    args = parse_args()

    # step 1: tell github about the file
    gh = add_github_reference(args)

    # step 2: upload file to s3
    if ('errors' in gh):
        print json.dumps(gh, indent=2)
    else:
        file_upload_success = post_file_to_s3(args.filepath, gh)

        # cleanup if upload failed
        if (False == file_upload_success):
            removed_ok = remove_github_reference(args, gh['id'])
            if (removed_ok):
                print "removed github reference"
            else:
                print "failed to remove github reference"


if __name__ == '__main__':
    main()

答案 5 :(得分:1)

hub基于Go的官方GitHub CLI工具

https://github.com/github/hub

首先安装Go。在Ubuntu上:https://askubuntu.com/questions/959932/installation-instructions-for-golang-1-9-into-ubuntu-16-04/1075726#1075726

然后安装hub

go get github.com/github/hub

没有Ubuntu软件包:https://github.com/github/hub/issues/718

然后从您的存储库中

hub release create -a prebuilt.zip -m 'release title' tag-name

此:

  • 第一次提示您输入密码,然后自动在本地创建和存储API令牌
  • 在名为tag-name的遥控器上创建一个非注释标签
  • 创建与该标签关联的发行版
  • prebuilt.zip作为附件上传

您还可以为您现有的API令牌提供GITHUB_TOKEN环境变量。

有关其他release操作,请参见:

hub release --help

hub de684cb613c47572cc9ec90d4fd73eef80aef09c上进行了测试。

没有任何外部依赖项的Python APIv3上传示例

用法:

GITHUB_TOKEN=<token> ./create-release username/reponame <tag-name> <path-to-upload>

脚本:

#!/usr/bin/env python3

import json
import os
import sys

from urllib.parse import urlencode
from urllib.request import Request, urlopen

repo = sys.argv[1]
tag = sys.argv[2]
upload_file = sys.argv[3]

token = os.environ['GITHUB_TOKEN']
url_template = 'https://{}.github.com/repos/' + repo + '/releases'

# Create.
_json = json.loads(urlopen(Request(
    url_template.format('api'),
    json.dumps({
        'tag_name': tag,
        'name': tag,
        'prerelease': True,
    }).encode(),
    headers={
        'Accept': 'application/vnd.github.v3+json',
        'Authorization': 'token ' + token,
    },
)).read().decode())
# This is not the tag, but rather some database integer identifier.
release_id = _json['id']

# Upload.
with open(upload_file, 'br') as myfile:
    content = myfile.read()
_json = json.loads(urlopen(Request(
    url_template.format('uploads') + '/' + str(release_id) + '/assets?' \
      + urlencode({'name': os.path.split(upload_file)[1]}),
    content,
    headers={
        'Accept': 'application/vnd.github.v3+json',
        'Authorization': 'token ' + token,
        'Content-Type': 'application/zip',
    },
)).read().decode())

发布和资产创建(如果已经存在)都将失败,并显示422。通过首先删除发行版或资产来解决此问题。这是an example

答案 6 :(得分:1)

2021 年更新:您可以创建 GitHub 操作自动化以从标签创建发布,然后使用运行器创建发布资产并将它们上传到发布。有关示例,请参阅 here

答案 7 :(得分:0)

对于那些使用gradle的人来说,插件gradle-github-plugin也允许创建版本并将文件附加到它们。

  1. 将插件添加到gradle.build
  2. plugins {
      id "co.riiid.gradle" version "X.Y.Z"
    }
    
    1. 配置上传。例如:
    2. github {
          owner = 'riiid'
          repo = 'gradle-github-plugin'
          token = 'XXXXXXXXXXXXXXXXXXXXX'
          tagName = '0.1.0'
          targetCommitish = 'master'
          name = 'v0.1.0'
          body = """# Project Name
      Write `release note` here.
      """
          assets = [
                  'app/build/outputs/apk/app-release.apk',
                  'app/build/outputs/mapping/release/mapping.txt',
                  'app/build/outputs',
                  ...
          ]
      }