@@ -3,15 +3,11 @@ const exec = require('@actions/exec');
33const path = require ( 'path' ) ;
44const fs = require ( 'fs' ) ;
55
6- // Using latest as default
7- const DEFAULT_FUNC_VERSION = 'latest' ;
8- const DEFAULT_BINARY_SOURCE = 'https://github.com/knative/func/releases/download' ;
9- const DEFAULT_LATEST_BINARY_SOURCE = 'https://github.com/knative/func/releases/latest/download' ;
6+ const LATEST = 'latest' ;
107
11- // Returns the binary name for the current OS/arch from GitHub releases
128function getOsBinName ( ) {
139 const osBinName = core . getInput ( 'binary' ) ;
14- if ( osBinName !== "" ) {
10+ if ( osBinName ) {
1511 return osBinName ;
1612 }
1713
@@ -24,14 +20,14 @@ function getOsBinName() {
2420 case 'ARM64' : return 'func_linux_arm64' ;
2521 case 'PPC64LE' : return 'func_linux_ppc64le' ;
2622 case 'S390X' : return 'func_linux_s390x' ;
27- default : throw new Error ( `unknown runner: ${ runnerArch } ` ) ;
23+ default : throw new Error ( `unknown runner arch : ${ runnerArch } ` ) ;
2824 }
2925 } else if ( runnerOS === 'macOS' ) {
3026 return runnerArch === 'X64' ? 'func_darwin_amd64' : 'func_darwin_arm64' ;
3127 } else if ( runnerOS === 'Windows' ) {
3228 return 'func_windows_amd64.exe' ;
3329 } else {
34- throw new Error ( `unknown runner: ${ runnerArch } ` ) ;
30+ throw new Error ( `unknown runner os : ${ runnerOS } ` ) ;
3531 }
3632}
3733
@@ -47,117 +43,110 @@ function resolveFullPathBin() {
4743 return path . resolve ( destination , bin ) ;
4844}
4945
50- // Normalizes version to release tag format: knative-vX.Y.Z
51- // Ex.: '1.16' or 'v1.16' will return 'knative-v1.16.0'
5246function smartVersionUpdate ( version ) {
53- const versionRegex = / ^ (?< knprefix > k n a t i v e - ) ? (?< prefix > v ? ) (?< major > \d + ) \. (?< minor > \d + ) ( \. (?< patch > \d + ) ) ? $ / ;
54- const match = version . match ( versionRegex ) ;
55- if ( ! match ) {
56- throw new Error ( `Invalid version format (${ version } ). Expected format: "1.16[.X]" or "v1.16[.X]"` ) ;
47+ const match = version . match ( / ^ (?: k n a t i v e - ) ? v ? ( \d + ) \. ( \d + ) (?: \. ( \d + ) ) ? $ / ) ;
48+ if ( ! match ) throw new Error ( `Invalid version format (${ version } ). Expected format: "1.16[.X]" or "v1.16[.X]"` ) ;
49+ return `knative-v${ match [ 1 ] } .${ match [ 2 ] } .${ match [ 3 ] ?? 0 } ` ;
50+ }
51+
52+ function resolveVersion ( ) {
53+ const version = core . getInput ( 'version' ) || LATEST ;
54+ if ( version . toLowerCase ( ) . trim ( ) === LATEST ) return LATEST ;
55+ return smartVersionUpdate ( version ) ;
56+ }
57+
58+ function resolveDownloadUrl ( version , binName ) {
59+ const binarySource = core . getInput ( 'binarySource' ) ;
60+ if ( binarySource ) {
61+ core . info ( `Using custom binary source: ${ binarySource } ` ) ;
62+ return binarySource ;
63+ }
64+
65+ if ( version === LATEST ) {
66+ core . info ( 'Using latest version...' ) ;
67+ return `https://github.com/knative/func/releases/latest/download/${ binName } ` ;
5768 }
58- const knprefix = 'knative-' ;
59- const prefix = 'v' ;
60- const patch = match . groups . patch ?? 0 ;
61- return `${ knprefix } ${ prefix } ${ match . groups . major } .${ match . groups . minor } .${ patch } ` ;
69+ core . info ( `Using specific version ${ version } ` ) ;
70+ return `https://github.com/knative/func/releases/download/${ version } /${ binName } ` ;
6271}
6372
64- // Downloads binary from release URL and makes it executable
6573async function downloadFuncBinary ( url , binPath ) {
6674 core . info ( `Downloading from: ${ url } ` ) ;
67-
6875 await exec . exec ( 'curl' , [ '-L' , '--fail' , '-o' , binPath , url ] ) ;
6976
7077 if ( ! fs . existsSync ( binPath ) ) {
7178 throw new Error ( "Download failed, couldn't find the binary on disk" ) ;
7279 }
73-
7480 if ( process . env . RUNNER_OS !== 'Windows' ) {
7581 await exec . exec ( 'chmod' , [ '+x' , binPath ] ) ;
7682 }
7783}
7884
79- // Adds binary directory to PATH for current and subsequent steps
8085function addBinToPath ( binPath ) {
8186 const dir = path . dirname ( binPath ) ;
8287 fs . appendFileSync ( process . env . GITHUB_PATH , `\n${ dir } ` ) ;
83-
8488 if ( ! process . env . PATH . split ( path . delimiter ) . includes ( dir ) ) {
85- process . env . PATH = process . env . PATH + path . delimiter + dir ;
89+ process . env . PATH += path . delimiter + dir ;
8690 core . info ( `${ dir } added to PATH` ) ;
8791 }
8892}
8993
90- // Resolve download url based on given input
91- // binName: name of func binary when it is to be constructed for full URL
92- // (when not using binarySource)
93- function resolveDownloadUrl ( binName ) {
94- const binarySource = core . getInput ( 'binarySource' ) ;
95- if ( binarySource !== "" ) {
96- core . info ( `Using custom binary source: ${ binarySource } ` ) ;
97- return binarySource ;
98- }
99-
100- const versionInput = core . getInput ( 'version' ) || DEFAULT_FUNC_VERSION ;
101- if ( versionInput . toLowerCase ( ) . trim ( ) === DEFAULT_FUNC_VERSION ) {
102- core . info ( "Using latest version..." ) ;
103- return buildUrlString ( DEFAULT_FUNC_VERSION ) ;
104- }
105- const version = smartVersionUpdate ( versionInput ) ;
106- core . info ( `Using specific version ${ version } ` ) ;
107- return buildUrlString ( version ) ;
108-
109- function buildUrlString ( version ) {
110- return version === DEFAULT_FUNC_VERSION
111- ? `${ DEFAULT_LATEST_BINARY_SOURCE } /${ binName } `
112- : `${ DEFAULT_BINARY_SOURCE } /${ version } /${ binName } ` ;
113- }
114- }
115-
116- async function run ( ) {
117- let osBinName ;
118- try {
119- osBinName = getOsBinName ( ) ;
120- } catch ( error ) {
121- core . setFailed ( error . message ) ;
94+ async function warnStaleVersion ( version ) {
95+ // Skip version check for 'latest' or custom binary source
96+ if ( version === LATEST || core . getInput ( 'binarySource' ) ) {
12297 return ;
12398 }
12499
125- let url ;
100+ let res ;
126101 try {
127- url = resolveDownloadUrl ( osBinName ) ;
102+ res = await fetch ( 'https://github.com/knative/func/releases/latest' , {
103+ method : 'HEAD' ,
104+ redirect : 'manual' ,
105+ } ) ;
128106 } catch ( error ) {
129- core . setFailed ( `Failed to resolve url: ${ error . message } ` ) ;
107+ core . warning ( `Failed to fetch latest version: ${ error . message } ` ) ;
108+ core . debug ( 'Skipping stale version check' ) ;
130109 return ;
131110 }
132111
133- let fullPathBin ;
134- try {
135- fullPathBin = resolveFullPathBin ( ) ;
136- } catch ( error ) {
137- core . setFailed ( error . message ) ;
112+ const loc = res . headers . get ( 'location' ) ;
113+ if ( ! loc ) {
114+ core . warning ( 'Could not determine latest version: no redirect location' ) ;
115+ core . debug ( 'Skipping stale version check' ) ;
138116 return ;
139117 }
140118
141- try {
142- await downloadFuncBinary ( url , fullPathBin ) ;
143- } catch ( error ) {
144- core . setFailed ( `Download failed: ${ error . message } ` ) ;
119+ const latest = loc . split ( '/' ) . pop ( ) ;
120+ // Convert version string "vX.Y" to number (X*100 + Y) for comparison,
121+ // e.g. "v1.21" → 121.
122+ // Returns null if no match, otherwise multiplies major by 100 and adds minor
123+ // (+ coerces string to number).
124+ const toNum = ( v ) => { const m = v . match ( / ( \d + ) \. ( \d + ) / ) ; return m && m [ 1 ] * 100 + + m [ 2 ] ; } ;
125+ const latestNum = toNum ( latest ) ;
126+ const versionNum = toNum ( version ) ;
127+ if ( versionNum == null || latestNum == null ) {
128+ core . debug ( 'could not parse version numbers to compare' ) ;
145129 return ;
146130 }
147-
148- try {
149- addBinToPath ( fullPathBin ) ;
150- } catch ( error ) {
151- core . setFailed ( error . message ) ;
152- return ;
131+ const diff = latestNum - versionNum ;
132+ if ( diff >= 3 ) {
133+ core . warning ( `You are using func ${ version } , which is ${ diff } minor versions behind the latest (${ latest } ). Upgrading is recommended.` ) ;
153134 }
135+ }
154136
155- try {
156- await exec . exec ( fullPathBin , [ 'version' ] ) ;
157- } catch ( error ) {
158- core . setFailed ( error . message ) ;
159- return ;
160- }
137+ async function run ( ) {
138+ const osBinName = getOsBinName ( ) ;
139+ const version = resolveVersion ( ) ;
140+ await warnStaleVersion ( version ) ;
141+
142+ const url = resolveDownloadUrl ( version , osBinName ) ;
143+ const fullPathBin = resolveFullPathBin ( ) ;
144+
145+ await downloadFuncBinary ( url , fullPathBin ) ;
146+ addBinToPath ( fullPathBin ) ;
147+
148+ await exec . exec ( fullPathBin , [ 'version' ] ) ;
161149}
162150
163- run ( ) ;
151+ run ( ) . catch ( error => core . setFailed ( error . message ) ) ;
152+
0 commit comments