Skip to content

Commit

Permalink
Merge pull request #32 from rvesse/custom-ext-matching
Browse files Browse the repository at this point in the history
  • Loading branch information
jaxxstorm committed Dec 13, 2022
2 parents a5d3a43 + 6a7d694 commit 402ff66
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 15 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/test.yml
@@ -1,6 +1,7 @@
name: "Test typescript-action"
on:
pull_request:
workflow_dispatch:
push:
branches:
- master
Expand Down Expand Up @@ -88,3 +89,58 @@ jobs:
platform: ${{ matrix.platform }}
arch: ${{ matrix.arch }}
- run: tfsec --version
opentelemetry-ocb:
strategy:
matrix:
version: [ "v0.62.1", "v0.62.0", "latest" ]
runs-on: [ "ubuntu-latest", "macos-latest"]
arch: [ "amd64" ]
include:
- runs-on: "ubuntu-latest"
platform: linux
- runs-on: "macos-latest"
platform: darwin
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v1
- run: npm ci
- run: npm run build
- uses: ./
with:
repo: open-telemetry/opentelemetry-collector
tag: ${{ matrix.version }}
platform: ${{ matrix.platform }}
arch: ${{ matrix.arch }}
extension-matching: disable
rename-to: ocb
chmod: 0755
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ocb version
mozilla-grcov:
strategy:
matrix:
version: [ "v0.8.12", "v0.8.7", "latest" ]
runs-on: [ "ubuntu-latest", "macos-latest" ]
arch: [ "x86_64" ]
include:
- runs-on: "ubuntu-latest"
platform: linux
- runs-on: "macos-latest"
platform: darwin
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v1
- run: npm ci
- run: npm run build
- uses: ./
with:
repo: mozilla/grcov
tag: ${{ matrix.version }}
platform: ${{ matrix.platform }}
arch: ${{ matrix.arch }}
extension: "\\.bz2"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: grcov --version

51 changes: 51 additions & 0 deletions README.md
Expand Up @@ -72,6 +72,57 @@ steps:
Caching helps avoid
[Rate limiting](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#requests-from-github-actions), since this action does not need to scan tags and releases on a cache hit. Caching currently is not expected to speed up installation.

### Changing Release File Extensions

As described below this action defaults to assuming that a release is either a `.tar.gz` or a `.zip` archive but this
may not always be true for all releases. For example a project might release a pure binary, a different archive format,
custom file extension etc.

This action can change its extension matching behaviour via the `extension-matching` and `extension` parameters. For
example to match on a `.bz2` extension:

```yaml
# ...
jobs:
my_job:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Github token scoped to job
steps:
- name: Install Mozilla grcov
uses: jaxxstorm/action-install-gh-release@v1.5.0
with: # Grab a specific file extension
repo: mozilla/grcov
tag: v0.8.12
extension: "\\.bz2"
```

Here the `extension` parameter is used to provide a regular expression for the file extension(s) you want to match. If
this is not specified then the action defaults to `\.(tag.gz|zip)`. Since this a regular expression being embedded into
YAML be aware that you may need to provide an extra level of character escaping, in the above example we have a `\\`
used in order to escape the backslash and get an actual `\.` (literal match of the period character) in the regular
expression passed into the action.

Alternatively if a project produces pure binary releases with no file extension then you can install as follows:

```yaml
# ...
jobs:
my_job:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Github token scoped to job
steps:
- name: Install Open Telemetry Collector Builder (ocb)
uses: jaxxstorm/action-install-gh-release@v1.5.0
with: # Grab a pure binary
repo: open-telemetry/opentelemetry-collector
tag: v0.62.1
extension-matching: disable
rename-to: ocb
chmod: 0755
```

Note the use of the `rename-to` and `chmod` parameters to rename the downloaded binary and make it executable.

## Finding a release

By default, this action will lookup the Platform and Architecture of the runner and use those values to interpolate and match a release package. **The release package name is first converted to lowercase**. The match pattern is:
Expand Down
13 changes: 13 additions & 0 deletions action.yml
Expand Up @@ -18,6 +18,19 @@ inputs:
arch:
description: "OS Architecture to match in release package. Specify this parameter if the repository releases do not follow a normal convention otherwise it will be auto-detected."
required: false
extension:
description: "Custom file extension to match in release package. Specify this parameter if the repository releases do not provide a .tar.gz or .zip format release."
required: false
extension-matching:
description: "Enable/disable file extension matching in release package. Specify this parameter if the repository releases do not have a file extension e.g. they are pure binaries."
required: false
default: enable
rename-to:
description: "When installing a release that is not an archive, e.g. a pure binary, this controls how the downloaded release asset is renamed. Specify this parameter if installing a non-archive release."
required: false
chmod:
description: "When installing a release that is not an archive, e.g. a pure binary, this controls how the downloaded release asset is chmod'd. Specify this parameter if installing a non-archive release and you need to change its permissions e.g. make it executable."
required: false
cache:
description: "When set to 'enable', caches the downloads of known tags with actions/cache"
required: false
Expand Down
98 changes: 91 additions & 7 deletions lib/main.js
Expand Up @@ -30,6 +30,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", { value: true });
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const cache = __importStar(require("@actions/cache"));
const core = __importStar(require("@actions/core"));
const tc = __importStar(require("@actions/tool-cache"));
Expand Down Expand Up @@ -105,6 +106,32 @@ function run() {
}
core.info(`==> System reported arch: ${os.arch()}`);
core.info(`==> Using arch: ${osArch}`);
// Determine File Extensions (if any)
const extMatching = core.getInput("extension-matching") === "enable";
let extension = core.getInput("extension");
let extMatchRegexForm = "";
if (extMatching) {
if (extension === "") {
extMatchRegexForm = "\.(tar.gz|zip)";
core.info(`==> Using default file extension matching: ${extMatchRegexForm}`);
}
else {
extMatchRegexForm = extension;
core.info(`==> Using custom file extension matching: ${extMatchRegexForm}`);
}
}
else {
core.info("==> File extension matching disabled");
}
// Determine whether renaming is in use
let renameTo = core.getInput("rename-to");
if (renameTo !== "") {
core.info(`==> Will rename downloaded release to ${renameTo}`);
}
let chmodTo = core.getInput("chmod");
if (chmodTo !== "") {
core.info(`==> Will chmod downloaded release asset to ${chmodTo}`);
}
let toolInfo = {
owner: owner,
project: project,
Expand Down Expand Up @@ -138,7 +165,7 @@ function run() {
});
}
let osMatchRegexForm = `(${osMatch.join('|')})`;
let re = new RegExp(`${osMatchRegexForm}.*${osMatchRegexForm}.*\.(tar.gz|zip)`);
let re = new RegExp(`${osMatchRegexForm}.*${osMatchRegexForm}.*${extMatchRegexForm}`);
let asset = getReleaseUrl.data.assets.find(obj => {
core.info(`searching for ${obj.name} with ${re.source}`);
let normalized_obj_name = obj.name.toLowerCase();
Expand All @@ -148,13 +175,62 @@ function run() {
const found = getReleaseUrl.data.assets.map(f => f.name);
throw new Error(`Could not find a release for ${tag}. Found: ${found}`);
}
const extractFn = getExtractFn(asset.name);
const url = asset.url;
core.info(`Downloading ${project} from ${url}`);
const binPath = yield tc.downloadTool(url, undefined, `token ${token}`, {
accept: 'application/octet-stream'
});
yield extractFn(binPath, dest);
const extractFn = getExtractFn(asset.name);
if (extractFn !== undefined) {
// Release is an archive file so extract it to the destination
const extractFlags = getExtractFlags(asset.name);
if (extractFlags !== undefined) {
core.info(`Attempting to extract archive with custom flags ${extractFlags}`);
yield extractFn(binPath, dest, extractFlags);
}
else {
yield extractFn(binPath, dest);
}
core.info(`Automatically extracted release asset ${asset.name} to ${dest}`);
if (renameTo !== "") {
core.warning("rename-to parameter ignored when installing a release from an archive");
}
if (chmodTo !== "") {
core.warning("chmod parameter ignored when installing a release from an archive");
}
}
else {
// As it wasn't an archive we've just downloaded it as a blob, this uses an auto-assigned name which will
// be a UUID which is likely meaningless to the caller. If they have specified a rename-to and a chmod
// parameter then this is where we apply those.
// Regardless of any rename-to parameter we still need to move the download to the actual destination
// otherwise it won't end up on the path as expected
core.warning(`Release asset ${asset.name} did not have a recognised file extension, unable to automatically extract it`);
try {
fs.mkdirSync(dest, { 'recursive': true });
const outputPath = path.join(dest, renameTo !== "" ? renameTo : path.basename(binPath));
core.info(`Created output directory ${dest}`);
try {
fs.renameSync(binPath, outputPath);
core.info(`Moved release asset ${asset.name} to ${outputPath}`);
if (chmodTo !== "") {
try {
fs.chmodSync(outputPath, chmodTo);
core.info(`chmod'd ${outputPath} to ${chmodTo}`);
}
catch (chmodErr) {
core.setFailed(`Failed to chmod ${outputPath} to ${chmodTo}: ${chmodErr}`);
}
}
}
catch (renameErr) {
core.setFailed(`Failed to move downloaded release asset ${asset.name} from ${binPath} to ${outputPath}: ${renameErr}`);
}
}
catch (err) {
core.setFailed(`Failed to create required output directory ${dest}`);
}
}
if (cacheEnabled && cacheKey !== undefined) {
try {
yield cache.saveCache([dest], cacheKey);
Expand All @@ -173,7 +249,7 @@ function run() {
}
}
core.addPath(dest);
core.info(`Successfully extracted ${project} to ${dest}`);
core.info(`Successfully installed ${project} to ${dest}`);
}
catch (error) {
if (error instanceof Error) {
Expand All @@ -186,7 +262,7 @@ function run() {
});
}
function cachePrimaryKey(info) {
// Currently not caching "latest" verisons of the tool.
// Currently not caching "latest" versions of the tool.
if (info.tag === "latest") {
return undefined;
}
Expand All @@ -204,14 +280,22 @@ function getCacheDirectory() {
return cacheDirectory;
}
function getExtractFn(assetName) {
if (assetName.endsWith('.tar.gz')) {
if (assetName.endsWith('.tar.gz') || assetName.endsWith('.tar.bz2')) {
return tc.extractTar;
}
else if (assetName.endsWith('.zip')) {
return tc.extractZip;
}
else {
throw new Error(`Unreachable error? File is neither .tar.gz nor .zip, got: ${assetName}`);
return undefined;
}
}
function getExtractFlags(assetName) {
if (assetName.endsWith('tar.bz2')) {
return "xj";
}
else {
return undefined;
}
}
run();

0 comments on commit 402ff66

Please sign in to comment.