Skip to content

Commit 49b375b

Browse files
committedMar 17, 2021
Import from internal
1 parent 44c99b7 commit 49b375b

12 files changed

+736
-0
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

‎Makefile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: build
2+
build:
3+
tsc && esbuild \
4+
--minify \
5+
--bundle \
6+
--sourcemap \
7+
'--define:process.env.NODE_ENV="production"' \
8+
--outdir=dist \
9+
--platform=node \
10+
--target=node12 \
11+
./src/main.ts

‎action.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: 'buf-setup'
2+
description: >
3+
Install buf for use in other jobs.
4+
inputs:
5+
version:
6+
description: 'The version of buf to setup.'
7+
required: true
8+
default: 'latest'
9+
runs:
10+
using: 'node12'
11+
main: './dist/main.js'

‎dist/main.js

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/main.js.map

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package-lock.json

+462
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "buf-setup",
3+
"version": "0.0.1",
4+
"dependencies": {
5+
"@actions/core": "^1.2.6",
6+
"@actions/github": "^4.0.0",
7+
"@actions/io": "^1.0.2",
8+
"@actions/tool-cache": "^1.6.1",
9+
"@types/node": "^14.14.35",
10+
"child_process": "^1.0.2"
11+
}
12+
}

‎src/buf.ts

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2020-2021 Buf Technologies, Inc.
2+
//
3+
// All rights reserved.
4+
5+
import * as os from 'os';
6+
import * as path from 'path';
7+
import * as core from '@actions/core';
8+
import * as tc from '@actions/tool-cache';
9+
import {Octokit} from '@octokit/core';
10+
import { Error, isError } from './error';
11+
12+
// versionPrefix is used in Github release names, and can
13+
// optionally be specified in the action's version parameter.
14+
const versionPrefix = "v";
15+
16+
export async function getBuf(version: string): Promise<string|Error> {
17+
const binaryPath = tc.find('buf', version, os.arch());
18+
if (binaryPath !== '') {
19+
core.info(`Found in cache @ ${binaryPath}`);
20+
return binaryPath;
21+
}
22+
23+
core.info(`Resolving the download URL for the current platform...`);
24+
const downloadURL = await getDownloadURL(version);
25+
if (isError(downloadURL)) {
26+
return downloadURL
27+
}
28+
29+
core.info(`Downloading buf version "${version}" from ${downloadURL}`);
30+
const downloadPath = await tc.downloadTool(downloadURL);
31+
core.info(`Successfully downloaded buf version "${version}" from ${downloadURL}`);
32+
33+
core.info('Extracting buf...');
34+
const extractPath = await tc.extractTar(downloadPath);
35+
core.info(`Successfully extracted buf to ${extractPath}`);
36+
37+
core.info('Adding buf to the cache...');
38+
const cacheDir = await tc.cacheDir(
39+
path.join(extractPath, 'buf'),
40+
'buf',
41+
version,
42+
os.arch()
43+
);
44+
core.info(`Successfully cached buf to ${cacheDir}`);
45+
46+
return cacheDir;
47+
}
48+
49+
// getDownloadURL resolves Buf's Github download URL for the
50+
// current architecture and platform.
51+
async function getDownloadURL(version: string): Promise<string|Error> {
52+
let architecture = '';
53+
switch (os.arch()) {
54+
// The available architectures can be found at:
55+
// https://nodejs.org/api/process.html#process_process_arch
56+
case 'x64':
57+
architecture = 'x86_64';
58+
break;
59+
default:
60+
return {
61+
errorMessage: `The "${os.arch()}" architecture is not supported with a Buf release.`
62+
};
63+
}
64+
let platform = '';
65+
switch (os.platform()) {
66+
// The available platforms can be found at:
67+
// https://nodejs.org/api/process.html#process_process_platform
68+
case 'linux':
69+
platform = 'Linux';
70+
break;
71+
default:
72+
return {
73+
errorMessage: `The "${os.platform()}" platform is not supported with a Buf release.`
74+
};
75+
}
76+
// The asset name is determined by the buf release structure found at:
77+
// https://github.com/bufbuild/buf/blob/8255257bd94c9f1b5faa27242211c5caad05be79/make/buf/scripts/release.bash#L102
78+
const assetName = `buf-${platform}-${architecture}.tar.gz`
79+
const octokit = new Octokit();
80+
const {data: releases} = await octokit.request(
81+
'GET /repos/{owner}/{repo}/releases',
82+
{
83+
owner: 'bufbuild',
84+
repo: 'buf',
85+
}
86+
);
87+
switch (version) {
88+
case 'latest':
89+
for (const asset of releases[0].assets) {
90+
if (assetName === asset.name) {
91+
return asset.browser_download_url;
92+
}
93+
}
94+
break;
95+
default:
96+
for (const release of releases) {
97+
if (releaseTagIsVersion(release.tag_name, version)) {
98+
for (const asset of release.assets) {
99+
if (assetName === asset.name) {
100+
return asset.browser_download_url;
101+
}
102+
}
103+
}
104+
}
105+
}
106+
return {
107+
errorMessage: `Unable to find Buf version "${version}" for platform "${platform}" and architecture "${architecture}".`
108+
};
109+
}
110+
111+
// releaseTagIsVersion returns true if the given Github release tag is equivalent
112+
// to the user-specified version. Github releases include the 'v' prefix, but the
113+
// `buf --version` does not. Thus, we permit both versions, e.g. v0.38.0 and 0.38.0.
114+
function releaseTagIsVersion(releaseTag: string, version: string): boolean {
115+
if (releaseTag.indexOf(versionPrefix) === 0) {
116+
releaseTag = releaseTag.slice(versionPrefix.length)
117+
}
118+
if (version.indexOf(versionPrefix) === 0) {
119+
version = version.slice(versionPrefix.length)
120+
}
121+
return releaseTag === version
122+
}

‎src/error.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2020-2021 Buf Technologies, Inc.
2+
//
3+
// All rights reserved.
4+
5+
import cp from 'child_process';
6+
7+
// Error is a generic error.
8+
export interface Error {
9+
errorMessage: string;
10+
}
11+
12+
// isError determines if the given value is an Error.
13+
// https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
14+
export function isError(value: any): value is Error {
15+
return (value as Error)?.errorMessage !== undefined;
16+
}

‎src/main.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright 2020-2021 Buf Technologies, Inc.
2+
//
3+
// All rights reserved.
4+
5+
import {run} from './run';
6+
7+
run();

‎src/run.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2020-2021 Buf Technologies, Inc.
2+
//
3+
// All rights reserved.
4+
5+
import cp from 'child_process';
6+
import * as path from 'path';
7+
import * as core from '@actions/core';
8+
import * as io from '@actions/io';
9+
import { getBuf } from './buf';
10+
import { Error, isError } from './error';
11+
12+
export async function run() {
13+
try {
14+
const result = await runSetup()
15+
if (isError(result)) {
16+
core.setFailed(result.errorMessage);
17+
}
18+
} catch (error) {
19+
// In case we ever fail to catch an error
20+
// in the call chain, we catch the error
21+
// and mark the build as a failure. The
22+
// user is otherwise prone to false positives.
23+
core.setFailed(error.message);
24+
}
25+
}
26+
27+
// runSetup runs the buf-setup action, and returns
28+
// a non-empty error if it fails.
29+
async function runSetup(): Promise<void|Error> {
30+
const version = core.getInput('version');
31+
if (version === '') {
32+
return {
33+
errorMessage: 'a version was not provided'
34+
};
35+
}
36+
37+
core.info(`Setting up buf version "${version}"`);
38+
const installDir = await getBuf(version);
39+
if (isError(installDir)) {
40+
return installDir
41+
}
42+
43+
core.info('Adding buf binary to PATH');
44+
core.addPath(path.join(installDir, 'bin'));
45+
const binaryPath = await io.which('buf', true);
46+
if (binaryPath === '') {
47+
return {
48+
errorMessage: 'buf was not found on PATH'
49+
};
50+
}
51+
52+
core.info(`Successfully setup buf version ${version}`);
53+
core.info(cp.execSync(`${binaryPath} --version`).toString());
54+
}

‎tsconfig.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"compilerOptions": {
3+
"rootDir": "./src",
4+
"lib": ["ES6"],
5+
"jsx": "preserve",
6+
"noImplicitAny": true,
7+
"esModuleInterop": true,
8+
"target": "es6",
9+
"allowJs": false,
10+
"skipLibCheck": true,
11+
"allowSyntheticDefaultImports": true,
12+
"strict": true,
13+
"forceConsistentCasingInFileNames": true,
14+
"module": "esnext",
15+
"moduleResolution": "node",
16+
"resolveJsonModule": true,
17+
"isolatedModules": true,
18+
"noEmit": true,
19+
"noImplicitReturns": true,
20+
"noFallthroughCasesInSwitch": true,
21+
"noUnusedParameters": true
22+
}
23+
}

0 commit comments

Comments
 (0)
Please sign in to comment.