|
1 | | -const core = require('@actions/core') |
2 | | -const github = require('@actions/github') |
3 | | -const fs = require('fs') |
4 | | -const path = require('path') |
5 | | -const fetch = require('node-fetch') |
| 1 | +import {getInput, setOutput, setFailed} from '@actions/core' |
| 2 | +import {context, GitHub} from '@actions/github' |
| 3 | +import * as fs from 'fs' |
| 4 | +import * as path from 'path' |
| 5 | +import fetch from 'node-fetch' |
| 6 | +import { ReposCreateReleaseResponse, ReposGetReleaseByTagResponse } from '@octokit/rest' |
6 | 7 |
|
7 | 8 | const GITHUB_TOKEN = getEnvVar('GITHUB_TOKEN') |
8 | 9 | const UPLOAD_GITHUB_TOKEN = getEnvVar('UPLOAD_GITHUB_TOKEN') |
9 | | -const INPUT_UPLOAD_OWNER_NAME = getEnvVar('INPUT_UPLOAD_OWNER_NAME') |
10 | | -const INPUT_UPLOAD_REPO_NAME = getEnvVar('INPUT_UPLOAD_REPO_NAME') |
11 | 10 |
|
12 | 11 | process.on('unhandledRejection', (reason: any, _: Promise<any>) => |
13 | 12 | handleError(reason) |
14 | 13 | ) |
15 | 14 | main().catch(handleError) |
16 | 15 |
|
17 | 16 | async function main() { |
18 | | - const nwo = getEnvVar('GITHUB_REPOSITORY') |
19 | | - const [owner, repo] = nwo.split('/') |
| 17 | + // Get the release from the current repository |
| 18 | + const tag = context.ref.replace('refs/tags/', '') |
| 19 | + const release = await getRelease(context.repo.owner, context.repo.repo, tag) |
20 | 20 |
|
| 21 | + // Create a new release in another repository |
| 22 | + const [targetOwner, targetRepo] = getInput('target-repo').split('/') |
| 23 | + let publicRelease: ReposCreateReleaseResponse | ReposCreateReleaseResponse |
21 | 24 | try { |
22 | | - // Get the release from the current repository |
23 | | - const release = await getRelease(owner, repo) |
24 | | - const asset = release.assets.find((a: any) => { |
25 | | - return a.name.match(/_darwin_amd64.tar.gz/i) |
26 | | - }) |
27 | | - const filePath = await downloadAsset(asset) |
| 25 | + publicRelease = await getRelease(targetOwner, targetRepo, tag) |
| 26 | + } catch (error) { |
| 27 | + if (error.status && error.status == 404) { |
| 28 | + publicRelease = await createRelease(targetOwner, targetRepo, release) |
| 29 | + } else { |
| 30 | + throw error |
| 31 | + } |
| 32 | + } |
28 | 33 |
|
29 | | - // Create a new release in another repository |
30 | | - const publicRelease = await createRelease(release) |
| 34 | + for (const asset of release.assets) { |
| 35 | + if (!(asset.name.match(/macOS/) || asset.name.match(/darwin/)) && !asset.name.match(/linux/)) { |
| 36 | + continue |
| 37 | + } |
| 38 | + const filePath = await downloadAsset(asset) |
| 39 | + for (const existingAsset of publicRelease.assets) { |
| 40 | + if (existingAsset.name == asset.name) { |
| 41 | + await deleteAsset(targetOwner, targetRepo, existingAsset) |
| 42 | + } |
| 43 | + } |
31 | 44 | const assetUrl = await uploadAsset(publicRelease, filePath) |
32 | | - core.setOutput('asset-url', assetUrl) |
33 | | - } catch (error) { |
34 | | - handleError(error) |
| 45 | + if (asset.name.match(/macOS/) || asset.name.match(/darwin/)) { |
| 46 | + setOutput('asset-url', assetUrl) |
| 47 | + } |
35 | 48 | } |
36 | 49 | } |
37 | 50 |
|
38 | | -async function getRelease(owner: string, repo: string) { |
39 | | - const octokit = new github.GitHub(GITHUB_TOKEN) |
40 | | - const tag = getEnvVar('GITHUB_REF').replace(/refs\/tags\//, '') |
| 51 | +async function getRelease(owner: string, repo: string, tag: string) { |
| 52 | + const octokit = new GitHub(GITHUB_TOKEN) |
41 | 53 | const response = await octokit.repos.getReleaseByTag({ owner, repo, tag }) |
42 | | - checkResponse(response) |
43 | 54 | return response.data |
44 | 55 | } |
45 | 56 |
|
46 | | -async function createRelease(release: any) { |
47 | | - const octokit = new github.GitHub(UPLOAD_GITHUB_TOKEN) |
48 | | - |
| 57 | +async function createRelease(owner: string, repo: string, release: ReposGetReleaseByTagResponse) { |
| 58 | + const octokit = new GitHub(UPLOAD_GITHUB_TOKEN) |
49 | 59 | const response = await octokit.repos.createRelease({ |
50 | | - owner: INPUT_UPLOAD_OWNER_NAME, |
51 | | - repo: INPUT_UPLOAD_REPO_NAME, |
| 60 | + owner, |
| 61 | + repo, |
52 | 62 | tag_name: release.tag_name, |
53 | 63 | name: release.name, |
54 | 64 | body: release.body, |
55 | | - target_commish: release.target_commish, |
| 65 | + target_commitish: release.target_commitish, |
56 | 66 | prerelease: release.prerelease, |
57 | 67 | draft: false, |
58 | 68 | }) |
59 | | - checkResponse(response) |
60 | 69 | return response.data |
61 | 70 | } |
62 | 71 |
|
63 | | -async function uploadAsset(release: any, filePath: string) { |
64 | | - const octokit = new github.GitHub(UPLOAD_GITHUB_TOKEN) |
| 72 | +async function uploadAsset(release: ReposGetReleaseByTagResponse | ReposCreateReleaseResponse, filePath: string) { |
| 73 | + const octokit = new GitHub(UPLOAD_GITHUB_TOKEN) |
65 | 74 | const response = await octokit.repos.uploadReleaseAsset({ |
66 | 75 | url: release.upload_url, |
67 | 76 | file: fs.readFileSync(filePath), |
68 | 77 | name: path.basename(filePath), |
69 | 78 | headers: { |
70 | | - 'content-type': 'application/gzip', |
| 79 | + 'content-type': 'application/octet-stream', |
71 | 80 | 'content-length': fs.statSync(filePath).size, |
72 | 81 | }, |
73 | 82 | }) |
74 | | - checkResponse(response) |
75 | | - return response.data.browser_download_url |
| 83 | + // this seems like a bug in Rest.js types |
| 84 | + const url: string = (<any>response.data).browser_download_url |
| 85 | + return url |
| 86 | +} |
| 87 | + |
| 88 | +interface Asset { |
| 89 | + id: number; |
| 90 | + url: string; |
| 91 | + name: string; |
76 | 92 | } |
77 | 93 |
|
78 | | -async function downloadAsset(asset: any) { |
79 | | - const options = { |
| 94 | +async function deleteAsset(owner: string, repo: string, asset: Asset) { |
| 95 | + const octokit = new GitHub(UPLOAD_GITHUB_TOKEN) |
| 96 | + await octokit.repos.deleteReleaseAsset({ |
| 97 | + owner, |
| 98 | + repo, |
| 99 | + asset_id: asset.id |
| 100 | + }) |
| 101 | +} |
| 102 | + |
| 103 | +async function downloadAsset(asset: Asset) { |
| 104 | + let response = await fetch(asset.url, { |
80 | 105 | redirect: 'manual', |
81 | 106 | headers: { |
82 | 107 | Authorization: `token ${GITHUB_TOKEN}`, |
83 | 108 | Accept: 'application/octet-stream', |
84 | 109 | }, |
85 | | - } |
| 110 | + }) |
86 | 111 |
|
87 | | - let response = await fetch(asset.url, options) |
88 | 112 | // Why didn't I just let fetch handle the redirect? Because that will |
89 | 113 | // will forwarded the Authorization header to S3 and AWS doesn't like that. |
90 | | - // For more deatails check out https://github.com/octokit/rest.js/issues/967 |
| 114 | + // For more details check out https://github.com/octokit/rest.js/issues/967 |
91 | 115 | if (response.status === 302) { |
92 | | - response = await fetch(response.headers.get('location'), { |
| 116 | + response = await fetch(response.headers.get('location') || '', { |
93 | 117 | headers: { Accept: 'application/octet-stream' }, |
94 | 118 | }) |
95 | 119 | } |
96 | 120 |
|
97 | 121 | if (response.status === 200) { |
98 | 122 | const data = await response.buffer() |
99 | 123 | fs.writeFileSync(asset.name, data) |
100 | | - return asset.name |
101 | 124 | } else { |
102 | 125 | throw new Error('failed to download asset: ' + (await response.text())) |
103 | 126 | } |
| 127 | + return asset.name |
104 | 128 | } |
105 | 129 |
|
106 | 130 | async function handleError(err: Error) { |
107 | 131 | console.error(err) |
108 | | - core.setFailed(err.message) |
109 | | -} |
110 | | - |
111 | | -function checkResponse(response: any) { |
112 | | - if (response.status >= 200 || response.status < 300) return |
113 | | - |
114 | | - throw new Error( |
115 | | - `Failed to run ${response.request.url}. Errors: ${response.errors}` |
116 | | - ) |
| 132 | + setFailed(err.message) |
117 | 133 | } |
118 | 134 |
|
119 | | -function getEnvVar(name: string) { |
| 135 | +function getEnvVar(name: string): string { |
120 | 136 | const envVar = process.env[name] |
121 | 137 | if (!envVar) { |
122 | 138 | throw new Error(`env var named "${name} is not set"`) |
|
0 commit comments