11const Core = require ( "@actions/core" ) ;
22const ToolCache = require ( "@actions/tool-cache" ) ;
33const Octokit = require ( "@octokit/request" ) ;
4+ const fetch = require ( "node-fetch" ) ;
45const Path = require ( "path" ) ;
56const ChildProcess = require ( "child_process" ) ;
67const Util = require ( "util" ) ;
78const FS = require ( "fs" ) . promises ;
89
10+ const exec = Util . promisify ( ChildProcess . exec ) ;
11+ const execFile = Util . promisify ( ChildProcess . execFile ) ;
12+
913async function run ( ) {
1014 try {
1115 const params = { } ;
@@ -24,6 +28,10 @@ async function run() {
2428 throw `Platform "${ getPlatform ( ) } " is not supported` ;
2529 }
2630 await func ( params ) ;
31+
32+ Core . info ( "[command]crystal --version" ) ;
33+ const { stdout} = await execFile ( "crystal" , [ "--version" ] ) ;
34+ Core . info ( stdout ) ;
2735 } catch ( error ) {
2836 Core . setFailed ( error ) ;
2937 process . exit ( 1 ) ;
@@ -69,7 +77,7 @@ async function installCrystalForLinux({
6977 arch = getArch ( ) ,
7078 destination = null ,
7179} ) {
72- checkVersion ( crystal , [ Latest , NumericVersion ] ) ;
80+ checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
7381 const suffixes = { "x86_64" : "linux-x86_64" , "x86" : "linux-i686" } ;
7482 checkArch ( arch , Object . keys ( suffixes ) ) ;
7583
@@ -86,13 +94,12 @@ async function installCrystalForMac({
8694 arch = "x86_64" ,
8795 destination = null ,
8896} ) {
89- checkVersion ( crystal , [ Latest , NumericVersion ] ) ;
97+ checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
9098 checkArch ( arch , [ "x86_64" ] ) ;
9199 return installBinaryRelease ( { crystal, suffix : "darwin-x86_64" , destination} ) ;
92100}
93101
94102async function installAptPackages ( packages ) {
95- const execFile = Util . promisify ( ChildProcess . execFile ) ;
96103 Core . info ( "Installing package dependencies" ) ;
97104 const args = [
98105 "-n" , "apt-get" , "install" , "-qy" , "--no-install-recommends" , "--no-upgrade" , "--" ,
@@ -105,20 +112,28 @@ async function installAptPackages(packages) {
105112}
106113
107114async function installBinaryRelease ( { crystal, suffix, destination} ) {
108- if ( crystal === Latest ) {
109- crystal = null ;
115+ let path ;
116+ if ( crystal === Nightly ) {
117+ path = await downloadCrystalNightly ( suffix , destination ) ;
118+ } else {
119+ if ( crystal === Latest ) {
120+ crystal = null ;
121+ }
122+ path = await downloadCrystalRelease ( suffix , crystal , destination ) ;
110123 }
111- const path = await downloadCrystalRelease ( { suffix, tag : crystal , destination} ) ;
112124
113125 Core . info ( "Setting up environment" ) ;
114126 Core . addPath ( Path . join ( path , "bin" ) ) ;
115127}
116128
117- async function downloadCrystalRelease ( { suffix, tag = null , destination = null } ) {
129+ const GitHubApiBase = "/repos/crystal-lang/crystal" ;
130+ const CircleApiBase = "https://circleci.com/api/v1.1/project/github/crystal-lang/crystal" ;
131+
132+ async function downloadCrystalRelease ( suffix , tag = null , destination = null ) {
118133 Core . info ( "Looking for latest Crystal release" ) ;
119134
120135 const releasesResp = await githubGet ( {
121- url : "/repos/crystal-lang/crystal /releases/" + ( tag ? "tags/" + tag : "latest" ) ,
136+ url : GitHubApiBase + " /releases/" + ( tag ? "tags/" + tag : "latest" ) ,
122137 } ) ;
123138 const release = releasesResp . data ;
124139 Core . info ( "Found " + release [ "html_url" ] ) ;
@@ -133,14 +148,47 @@ async function downloadCrystalRelease({suffix, tag = null, destination = null})
133148 return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
134149}
135150
151+ async function downloadCrystalNightly ( suffix , destination = null ) {
152+ Core . info ( "Looking for latest Crystal build" ) ;
153+
154+ let build ;
155+ for ( let offset = 0 ; ; ) {
156+ const req = `/tree/master?filter=successful&shallow=true&limit=100&offset=${ offset } ` ;
157+ const resp = await fetch ( CircleApiBase + req ) ;
158+ const builds = await resp . json ( ) ;
159+ build = builds . find ( ( b ) => b [ "workflows" ] [ "job_name" ] === "dist_artifacts" ) ;
160+ if ( build ) {
161+ break ;
162+ }
163+ offset += builds . length ;
164+ if ( offset >= 1000 ) {
165+ throw "Could not find a matching nightly build" ;
166+ }
167+ }
168+ Core . info ( "Found " + build [ "build_url" ] ) ;
169+ Core . setOutput ( "crystal" , build [ "vcs_revision" ] ) ;
170+
171+ const req = `/${ build [ "build_num" ] } /artifacts` ;
172+ const resp = await fetch ( CircleApiBase + req ) ;
173+ const artifacts = await resp . json ( ) ;
174+ const artifact = artifacts . find ( ( a ) => a [ "path" ] . endsWith ( `-${ suffix } .tar.gz` ) ) ;
175+ Core . info ( "Found " + artifact [ "url" ] ) ;
176+
177+ Core . info ( "Downloading Crystal build" ) ;
178+ const downloadedPath = await ToolCache . downloadTool ( artifact [ "url" ] ) ;
179+
180+ Core . info ( "Extracting Crystal build" ) ;
181+ return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
182+ }
183+
136184async function installCrystalForWindows ( {
137185 crystal = Nightly ,
138186 arch = "x86_64" ,
139187 destination = null ,
140188} ) {
141189 checkVersion ( crystal , [ Nightly ] ) ;
142190 checkArch ( arch , [ "x86_64" ] ) ;
143- const path = await downloadCrystalForWindows ( destination ) ;
191+ const path = await downloadCrystalNightlyForWindows ( destination ) ;
144192 await setupCrystalForWindows ( path ) ;
145193}
146194
@@ -169,7 +217,6 @@ const outputSep = "---";
169217const vcvarsPath = String . raw `C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat` ;
170218
171219async function variablesForVCBuildTools ( ) {
172- const exec = Util . promisify ( ChildProcess . exec ) ;
173220 const command = `set && echo ${ outputSep } && "${ vcvarsPath } " >nul && set` ;
174221 Core . info ( `[command]cmd /c "${ command } "` ) ;
175222 const { stdout} = await exec ( command , { shell : "cmd" } ) ;
@@ -197,11 +244,11 @@ function* getChangedVars(lines) {
197244 }
198245}
199246
200- async function downloadCrystalForWindows ( destination = null ) {
247+ async function downloadCrystalNightlyForWindows ( destination = null ) {
201248 Core . info ( "Looking for latest Crystal build" ) ;
202249
203250 const runsResp = await githubGet ( {
204- url : "/repos/crystal-lang/crystal /actions/workflows/win.yml/runs?branch=master&event=push&status=success",
251+ url : GitHubApiBase + " /actions/workflows/win.yml/runs?branch=master&event=push&status=success",
205252 "per_page" : 1 ,
206253 } ) ;
207254 const [ workflowRun ] = runsResp . data [ "workflow_runs" ] ;
@@ -211,7 +258,7 @@ async function downloadCrystalForWindows(destination = null) {
211258
212259 const fetchSrcTask = async ( destDir ) => {
213260 const zipballLinkResp = await githubGet ( {
214- url : "/repos/crystal-lang/crystal /zipball/:ref",
261+ url : GitHubApiBase + " /zipball/:ref",
215262 "ref" : ref ,
216263 request : { redirect : "manual" } ,
217264 } ) ;
@@ -227,13 +274,13 @@ async function downloadCrystalForWindows(destination = null) {
227274
228275 const fetchExeTask = async ( ) => {
229276 const artifactsResp = await githubGet ( {
230- url : "/repos/crystal-lang/crystal /actions/runs/:run_id/artifacts",
277+ url : GitHubApiBase + " /actions/runs/:run_id/artifacts",
231278 "run_id" : runId ,
232279 } ) ;
233280 const artifact = artifactsResp . data [ "artifacts" ] . find ( ( x ) => x . name === "crystal" ) ;
234281
235282 const artifactLinkResp = await githubGet ( {
236- url : "/repos/crystal-lang/crystal /actions/artifacts/:artifact_id/zip",
283+ url : GitHubApiBase + " /actions/artifacts/:artifact_id/zip",
237284 "artifact_id" : artifact . id ,
238285 request : { redirect : "manual" } ,
239286 } ) ;
0 commit comments