Skip to content

Commit 675fe07

Browse files
authored
Merge pull request #1 from functions-dev/push-vrrzxxrmqkrn
cleanup & fixes & general improvements
2 parents e9f9397 + 02a6e4c commit 675fe07

305 files changed

Lines changed: 216 additions & 395414 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-action.yml

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,70 @@
11
name: test-action
2-
on: [pull_request,workflow_dispatch]
2+
on: [pull_request, workflow_dispatch]
33

44
jobs:
5-
func:
5+
test-default:
6+
strategy:
7+
matrix:
8+
os: [ubuntu-latest,windows-latest,macos-latest]
9+
runs-on: ${{ matrix.os }}
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: Setup func CLI
13+
uses: ./
14+
- run: func version
15+
16+
test-custom-version:
17+
runs-on: ubuntu-latest
18+
env:
19+
TEST_VERSION: '1.19.0'
20+
VERSION_OFFSET: 27 # internal version = minor + offset (v1.19 → v0.46)
21+
steps:
22+
- uses: actions/checkout@v4
23+
- name: Setup func CLI with custom version
24+
uses: ./
25+
with:
26+
version: 'v${{ env.TEST_VERSION }}'
27+
- name: Verify version
28+
run: |
29+
MINOR=$(echo "$TEST_VERSION" | cut -d. -f2)
30+
INTERNAL=$((MINOR + VERSION_OFFSET))
31+
func version | grep -q "v0.${INTERNAL}"
32+
33+
test-custom-name:
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v4
37+
- name: Setup func CLI with custom name
38+
uses: ./
39+
with:
40+
name: 'my-func'
41+
- run: my-func version
42+
43+
test-custom-destination:
44+
runs-on: ubuntu-latest
45+
steps:
46+
- uses: actions/checkout@v4
47+
- name: Setup func CLI with custom destination
48+
uses: ./
49+
with:
50+
destination: '/tmp/func-bin'
51+
- run: func version
52+
- name: Verify func using path
53+
run: /tmp/func-bin/func version
54+
55+
test-invalid-version:
656
runs-on: ubuntu-latest
757
steps:
8-
- uses: functions-dev/action@main
58+
- uses: actions/checkout@v4
59+
- name: Setup func CLI with non-existing version (should fail)
60+
id: invalid-version
61+
uses: ./
62+
with:
63+
version: 'v99.99.99'
64+
continue-on-error: true
65+
- name: Verify action failed
66+
run: |
67+
if [ "${{ steps.invalid-version.outcome }}" != "failure" ]; then
68+
echo "Expected action to fail with invalid version"
69+
exit 1
70+
fi

README.md

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
# Functions as Github Action!
2-
Functions' Github Action, so you can get Functions in your workflows!
3-
Automatically determines what os the GH Runner has to get the right binary.
4-
You can change where you want the `func` to be downloaded with `destination` - regardless, it will be in `$PATH`!
5-
By default, uses latest version, but you can specify which one you want using `version`.
1+
# Func Action
2+
3+
GitHub Action to download and setup the func CLI. Automatically detects OS and architecture.
4+
5+
## Usage
66

7-
`action.yml` -- action yaml with descriptions
87
```yaml
9-
name: 'Func Action'
10-
description: 'This action does custom stuff for it is custom'
11-
inputs:
12-
name:
13-
description: '(optional) Name of the Function binary. It will be available in the runner under this name(defaults to "func")'
14-
binary:
15-
description: '(optional) Binary you want to download (exact string expected), otherwise will be determined via the OS of GH Runner'
16-
version:
17-
description: '(optional) Provide version to download. Any version in release pages works https://github.com/knative/func/tags'
18-
destination:
19-
description: '(optional) Provide a path where to move the desired downloaded binary, otherwise cwd is used'
20-
runs:
21-
using: 'node20'
22-
main: 'index.js'
8+
- uses: functions-dev/action@main
9+
with:
10+
version: 'v1.20.0' # optional
11+
name: 'func' # optional
2312
```
13+
14+
## Inputs
15+
16+
| Input | Description | Default |
17+
|-------|-------------|---------|
18+
| `version` | Version to download (e.g. `v1.20.0`) | recent stable |
19+
| `name` | Binary name | `func` |
20+
| `binary` | Specific binary to download | auto-detected |
21+
| `destination` | Download directory | cwd |

action.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
name: 'Func Action'
2-
description: 'This action does custom stuff for it is custom'
2+
description: 'Downloads and sets up the func CLI for Functions'
33
inputs:
44
name:
5-
description: '(optional) Name of the Function binary. It will be available in the runner under this name(defaults to "func")'
5+
description: '(optional) Name of the binary (defaults to "func")'
66
binary:
77
description: '(optional) Binary you want to download (exact string expected), otherwise will be determined via the OS of GH Runner'
88
version:
99
description: '(optional) Provide version to download. Any version in release pages works https://github.com/knative/func/tags'
1010
destination:
1111
description: '(optional) Provide a path where to move the desired downloaded binary, otherwise cwd is used'
12+
binarySource:
13+
description: '(optional) Base URL for downloading binaries. Defaults to GitHub releases. Pattern: <url-base>/<version>/<os-bin-name>'
1214
runs:
1315
using: 'node20'
1416
main: 'index.js'

index.js

Lines changed: 70 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
const core = require('@actions/core');
2-
const exec = require('@actions/exec')
3-
const path = require('path')
2+
const exec = require('@actions/exec');
3+
const path = require('path');
44
const fs = require('fs');
55

6+
// Static version - update manually when new func releases are available
7+
const DEFAULT_FUNC_VERSION = 'knative-v1.20.1';
68

7-
// change this accordingly
8-
const DEFAULT_FUNC_VERSION = 'knative-v1.16.1'
9-
10-
// detect os system in Github Actions and determine binary name
9+
// Returns the binary name for the current OS/arch from GitHub releases
1110
function getOsBinName() {
1211
const runnerOS = process.env.RUNNER_OS;
1312
const runnerArch = process.env.RUNNER_ARCH;
@@ -23,106 +22,93 @@ function getOsBinName() {
2322
} else if (runnerOS === 'macOS') {
2423
return runnerArch === 'X64' ? 'func_darwin_amd64' : 'func_darwin_arm64';
2524
} else if (runnerOS === 'Windows') {
26-
return 'func_windows_amd64';
25+
return 'func_windows_amd64.exe';
2726
} else {
2827
return 'unknown';
2928
}
3029
}
3130

32-
// smartVersionParse will check validity of given version and fill in the parts
33-
// to make it correct if possible.
34-
// Ex.: '1.16' or 'v1.16' will return 'v1.16.0'
35-
function smartVersionUpdate(version){
36-
versionRegex = /^(?<knprefix>knative-)?(?<prefix>v?)(?<major>\d+)\.(?<minor>\d+)(.(?<patch>\d+))?$/;
37-
let match = version.match(versionRegex);
38-
if (match){
39-
if (match.groups.knprefix == undefined){
40-
match.groups.knprefix = "";
41-
}
42-
const prefix = 'v';
43-
if (match.groups.patch == undefined) {
44-
match.groups.patch = 0;
45-
}
46-
return `${match.groups.knprefix}${prefix}${match.groups.major}.${match.groups.minor}.${match.groups.patch}`;
47-
}
48-
49-
core.setFailed(`Invalid version format (${version}). Expected format: "1.16[.X]" or "v1.16[.X]"`);
50-
return undefined;
31+
// Normalizes version to release tag format: knative-vX.Y.Z
32+
// Ex.: '1.16' or 'v1.16' will return 'knative-v1.16.0'
33+
function smartVersionUpdate(version) {
34+
const versionRegex = /^(?<knprefix>knative-)?(?<prefix>v?)(?<major>\d+)\.(?<minor>\d+)(.(?<patch>\d+))?$/;
35+
const match = version.match(versionRegex);
36+
if (!match) {
37+
throw new Error(`Invalid version format (${version}). Expected format: "1.16[.X]" or "v1.16[.X]"`);
38+
}
39+
const knprefix = 'knative-';
40+
const prefix = 'v';
41+
const patch = match.groups.patch ?? 0;
42+
return `${knprefix}${prefix}${match.groups.major}.${match.groups.minor}.${patch}`;
5143
}
5244

53-
/**
54-
* @param {string} url - Full url to be curled
55-
* @param {string} binPath - Full target path of the binary
56-
*/
57-
// download func, set as executable
58-
async function cmdConstructAndRun(url,binPath){
59-
const cmd = `curl -L -o "${binPath}" "${url}"`;
60-
await exec.exec(cmd);
61-
62-
//check if downloaded successfully
63-
if (!fs.existsSync(binPath)){
64-
core.setFailed("Download failed, couldn't find the binary on disk");
45+
const DEFAULT_BINARY_SOURCE = 'https://github.com/knative/func/releases/download';
46+
47+
// Downloads binary from release URL and makes it executable
48+
async function downloadFuncBinary(version, osBinName, binPath, binarySource) {
49+
const url = `${binarySource}/${version}/${osBinName}`;
50+
core.info(`Downloading from: ${url}`);
51+
52+
await exec.exec('curl', ['-L', '--fail', '-o', binPath, url]);
53+
54+
if (!fs.existsSync(binPath)) {
55+
throw new Error("Download failed, couldn't find the binary on disk");
6556
}
6657

67-
await exec.exec(`chmod +x ${binPath}`);
58+
if (process.env.RUNNER_OS !== 'Windows') {
59+
await exec.exec('chmod', ['+x', binPath]);
60+
}
6861
}
6962

70-
/**
71-
* @param {string} binPath - full path to Func binary
72-
* */
73-
async function addBinToPath(binPath){
74-
dir = path.dirname(binPath)
75-
// Write to $GITHUB_PATH, making it available for subsequent steps
63+
// Adds binary directory to PATH for current and subsequent steps
64+
async function addBinToPath(binPath) {
65+
const dir = path.dirname(binPath);
7666
fs.appendFileSync(process.env.GITHUB_PATH, `\n${dir}`);
7767

78-
// add only if its not in PATH yet
79-
if (!process.env.PATH.includes(dir)){
68+
if (!process.env.PATH.includes(dir)) {
8069
process.env.PATH = process.env.PATH + path.delimiter + dir;
81-
core.info(`dir ${dir} added to $PATH`);
70+
core.info(`${dir} added to PATH`);
71+
}
72+
}
73+
74+
async function run() {
75+
const osBinName = core.getInput('binary') || getOsBinName();
76+
if (osBinName === "unknown") {
77+
core.setFailed("Invalid os binary determination, try setting it specifically using 'binary'");
78+
return;
79+
}
80+
81+
const versionInput = core.getInput('version') || DEFAULT_FUNC_VERSION;
82+
const destination = core.getInput('destination') || process.cwd();
83+
const binarySource = core.getInput('binarySource') || DEFAULT_BINARY_SOURCE;
84+
let bin = core.getInput('name') || 'func';
85+
if (process.env.RUNNER_OS === 'Windows' && !bin.endsWith('.exe')) {
86+
bin += '.exe';
8287
}
83-
}
8488

85-
// -------------------------------------------------------------------------- \\
86-
async function run(){
89+
let version;
8790
try {
91+
version = smartVersionUpdate(versionInput);
92+
} catch (error) {
93+
core.setFailed(error.message);
94+
return;
95+
}
8896

89-
// Fetch value of inputs specified in action.yml or use defaults
97+
if (!fs.existsSync(destination)) {
98+
fs.mkdirSync(destination, { recursive: true });
99+
}
90100

91-
// osBin refers to the exact name match of an existing binary available to
92-
// download
93-
const osBin = core.getInput('binary') || getOsBinName();
94-
if (osBin == "unknown"){
95-
core.setFailed("Invalid os binary determination, try setting it specifically using 'binary'");
96-
}
97-
// version to be downloaded
98-
let version = core.getInput('version') || DEFAULT_FUNC_VERSION
99-
// destination is a directory where to download the Func
100-
const destination = core.getInput('destination') || process.cwd();
101-
// bin refers to the name of the binary (Func) that will be downloaded (this
102-
// is what it will be called)
103-
const bin = core.getInput('name') || 'func';
104-
105-
version = smartVersionUpdate(version);
106-
107-
var url = `https://github.com/knative/func/releases/download/${version}/${osBin}`;
108-
console.log(`URL: ${url}`);
109-
110-
fullPathBin = path.resolve(destination,bin);
111-
112-
// download Func
113-
await cmdConstructAndRun(url,fullPathBin);
114-
115-
// add final binary to PATH (directory where the bin is ) and add it to
116-
// GITHUB_PATH so it can be used bo subsequent 'runs'
117-
await addBinToPath(fullPathBin);
118-
119-
await exec.exec("ls -la")
120-
// run 'func version' as a test
121-
await exec.exec(`${bin} version`);
101+
const fullPathBin = path.resolve(destination, bin);
122102

103+
try {
104+
await downloadFuncBinary(version, osBinName, fullPathBin, binarySource);
123105
} catch (error) {
124-
core.setFailed(error.message);
106+
core.setFailed(`Download failed: ${error.message}`);
107+
return;
125108
}
109+
110+
await addBinToPath(fullPathBin);
111+
await exec.exec(fullPathBin, ['version']);
126112
}
127113

128114
run();

0 commit comments

Comments
 (0)