├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github └── workflows │ ├── licensed.yml │ └── workflow.yml ├── .gitignore ├── .licensed.yml ├── .licenses └── npm │ ├── @actions │ ├── core.dep.yml │ ├── exec.dep.yml │ ├── glob.dep.yml │ ├── http-client.dep.yml │ ├── io.dep.yml │ └── tool-cache.dep.yml │ ├── argparse.dep.yml │ ├── balanced-match.dep.yml │ ├── brace-expansion.dep.yml │ ├── concat-map.dep.yml │ ├── esprima.dep.yml │ ├── js-yaml.dep.yml │ ├── minimatch.dep.yml │ ├── semver.dep.yml │ ├── sprintf-js.dep.yml │ ├── tunnel.dep.yml │ └── uuid.dep.yml ├── .lintstagedrc.js ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── __tests__ ├── find-haskell.test.ts ├── hello.hs └── project │ ├── Main.hs │ ├── Setup.hs │ └── project.cabal ├── action.yml ├── dist ├── action.yml └── index.js ├── docs └── contributors.md ├── env.d.ts ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── installer.ts ├── opts.ts ├── setup-haskell.ts └── versions.json └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .out/ 3 | __tests__/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": ["jest", "@typescript-eslint"], 4 | "extends": ["plugin:github/typescript"], 5 | "parser": "@typescript-eslint/parser", 6 | "parserOptions": { 7 | "ecmaVersion": 2019, 8 | "sourceType": "module", 9 | "project": "./tsconfig.json" 10 | }, 11 | "rules": { 12 | "eslint-comments/no-use": "off", 13 | "import/no-namespace": "off", 14 | "no-unused-vars": "off", 15 | "@typescript-eslint/no-unused-vars": "error", 16 | "@typescript-eslint/explicit-member-accessibility": [ 17 | "warn", 18 | {"accessibility": "no-public"} 19 | ], 20 | "@typescript-eslint/no-require-imports": "error", 21 | "@typescript-eslint/array-type": "warn", 22 | "@typescript-eslint/await-thenable": "error", 23 | "camelcase": "off", 24 | "@typescript-eslint/explicit-function-return-type": [ 25 | "warn", 26 | {"allowExpressions": true} 27 | ], 28 | "@typescript-eslint/no-array-constructor": "error", 29 | "@typescript-eslint/no-empty-interface": "warn", 30 | "@typescript-eslint/no-explicit-any": "warn", 31 | "@typescript-eslint/no-for-in-array": "error", 32 | "@typescript-eslint/no-misused-new": "warn", 33 | "@typescript-eslint/no-namespace": "warn", 34 | "@typescript-eslint/no-non-null-assertion": "warn", 35 | "@typescript-eslint/no-unnecessary-qualifier": "warn", 36 | "@typescript-eslint/no-unnecessary-type-assertion": "warn", 37 | "@typescript-eslint/no-useless-constructor": "warn", 38 | "@typescript-eslint/no-var-requires": "error", 39 | "@typescript-eslint/prefer-for-of": "warn", 40 | "@typescript-eslint/prefer-function-type": "warn", 41 | "@typescript-eslint/prefer-includes": "warn", 42 | "@typescript-eslint/prefer-string-starts-ends-with": "warn", 43 | "@typescript-eslint/promise-function-async": "warn", 44 | "@typescript-eslint/require-array-sort-compare": "warn", 45 | "@typescript-eslint/restrict-plus-operands": "error", 46 | "semi": "off", 47 | "@typescript-eslint/unbound-method": "error", 48 | "prettier/prettier": "off" 49 | }, 50 | "env": { 51 | "node": true, 52 | "es6": true, 53 | "jest/globals": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .licenses/** -diff linguist-generated=true -------------------------------------------------------------------------------- /.github/workflows/licensed.yml: -------------------------------------------------------------------------------- 1 | name: Licensed 2 | 3 | on: 4 | push: {branches: main} 5 | pull_request: {branches: main} 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | name: Check licenses 11 | steps: 12 | - uses: actions/checkout@v2 13 | - run: npm ci 14 | - name: Install licensed 15 | run: | 16 | cd $RUNNER_TEMP 17 | curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/2.12.2/licensed-2.12.2-linux-x64.tar.gz 18 | sudo tar -xzf licensed.tar.gz 19 | sudo mv licensed /usr/local/bin/licensed 20 | - run: licensed status -------------------------------------------------------------------------------- /.github/workflows/workflow.yml: -------------------------------------------------------------------------------- 1 | name: build-test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - '**.md' 8 | pull_request: 9 | paths-ignore: 10 | - '**.md' 11 | jobs: 12 | test: 13 | name: Unit Tests - ${{ matrix.os }} 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, macOS-latest, windows-latest] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Set Node.js 12 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: 12 27 | # http://www.tiernok.com/posts/2019/faster-npm-installs-during-ci/ 28 | - run: npm ci --prefer-offline --no-audit --progress=false 29 | - run: npm test 30 | 31 | install-haskell: 32 | name: GHC ${{ matrix.ghc }}, Cabal ${{ matrix.cabal }} - ${{ matrix.os }} 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [ubuntu-latest, macOS-latest, windows-latest] 38 | ghc: ['latest', '8.4.4'] 39 | cabal: ['latest'] 40 | include: 41 | - os: ubuntu-latest 42 | ghc: '7.10.3' 43 | cabal: '3.0.0.0' 44 | - os: ubuntu-latest 45 | ghc: '8.2.2' 46 | cabal: '2.0' 47 | 48 | steps: 49 | - uses: actions/checkout@v2 50 | - uses: ./ 51 | with: 52 | ghc-version: ${{ matrix.ghc }} 53 | cabal-version: ${{ matrix.cabal }} 54 | - run: | 55 | runhaskell --version 56 | runhaskell __tests__/hello.hs 57 | - shell: bash 58 | run: cd __tests__/project && cabal build && cabal run 59 | - run: | 60 | cabal --version 61 | ghc --version 62 | - shell: bash 63 | if: matrix.ghc != 'latest' 64 | # this check depends on the ghc versions being "exact" in the matrix 65 | run: | 66 | [[ $(ghc --numeric-version) == ${{ matrix.ghc }} ]] 67 | 68 | install-stack: 69 | name: Stack ${{ matrix.stack }} ${{ matrix.os }} 70 | runs-on: ${{ matrix.os }} 71 | strategy: 72 | fail-fast: false 73 | matrix: 74 | os: [ubuntu-latest, macOS-latest, windows-latest] 75 | stack: ['latest', '1.9.1'] 76 | 77 | steps: 78 | - uses: actions/checkout@v2 79 | 80 | - uses: ./ 81 | with: 82 | enable-stack: true 83 | stack-no-global: true 84 | stack-version: ${{ matrix.stack }} 85 | - run: | 86 | stack --version 87 | stack 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist-newstyle 3 | .out 4 | .eslintcache 5 | -------------------------------------------------------------------------------- /.licensed.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | npm: true 3 | 4 | allowed: 5 | - apache-2.0 6 | - bsd-2-clause 7 | - bsd-3-clause 8 | - isc 9 | - mit 10 | - cc0-1.0 11 | - unlicense 12 | - 0bsd 13 | 14 | reviewed: 15 | npm: 16 | - sax -------------------------------------------------------------------------------- /.licenses/npm/@actions/core.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/core" 3 | version: 1.2.6 4 | type: npm 5 | summary: Actions core lib 6 | homepage: https://github.com/actions/toolkit/tree/main/packages/core 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: |- 11 | The MIT License (MIT) 12 | 13 | Copyright 2019 GitHub 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | notices: [] 21 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/exec.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/exec" 3 | version: 1.0.4 4 | type: npm 5 | summary: Actions exec lib 6 | homepage: https://github.com/actions/toolkit/tree/master/packages/exec 7 | license: mit 8 | licenses: 9 | - sources: Auto-generated MIT license text 10 | text: | 11 | MIT License 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | notices: [] 31 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/glob.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/glob" 3 | version: 0.1.0 4 | type: npm 5 | summary: Actions glob lib 6 | homepage: https://github.com/actions/toolkit/tree/master/packages/glob 7 | license: mit 8 | licenses: 9 | - sources: Auto-generated MIT license text 10 | text: | 11 | MIT License 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | notices: [] 31 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/http-client.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/http-client" 3 | version: 1.0.8 4 | type: npm 5 | summary: Actions Http Client 6 | homepage: https://github.com/actions/http-client#readme 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | Actions Http Client for Node.js 12 | 13 | Copyright (c) GitHub, Inc. 14 | 15 | All rights reserved. 16 | 17 | MIT License 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 20 | associated documentation files (the "Software"), to deal in the Software without restriction, 21 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 23 | subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 28 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 29 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 30 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 31 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | notices: [] 33 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/io.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/io" 3 | version: 1.0.2 4 | type: npm 5 | summary: Actions io lib 6 | homepage: https://github.com/actions/toolkit/tree/master/packages/io 7 | license: mit 8 | licenses: 9 | - sources: Auto-generated MIT license text 10 | text: | 11 | MIT License 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | notices: [] 31 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/tool-cache.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/tool-cache" 3 | version: 1.5.5 4 | type: npm 5 | summary: Actions tool-cache lib 6 | homepage: https://github.com/actions/toolkit/tree/master/packages/tool-cache 7 | license: mit 8 | licenses: 9 | - sources: Auto-generated MIT license text 10 | text: | 11 | MIT License 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | notices: [] 31 | -------------------------------------------------------------------------------- /.licenses/npm/argparse.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: argparse 3 | version: 1.0.10 4 | type: npm 5 | summary: Very powerful CLI arguments parser. Native port of argparse - python's options 6 | parsing library 7 | homepage: https://github.com/nodeca/argparse#readme 8 | license: mit 9 | licenses: 10 | - sources: LICENSE 11 | text: | 12 | (The MIT License) 13 | 14 | Copyright (C) 2012 by Vitaly Puzrin 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in 24 | all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | THE SOFTWARE. 33 | - sources: README.md 34 | text: |- 35 | Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin). 36 | Released under the MIT license. See 37 | [LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details. 38 | notices: [] 39 | -------------------------------------------------------------------------------- /.licenses/npm/balanced-match.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: balanced-match 3 | version: 1.0.0 4 | type: npm 5 | summary: Match balanced character pairs, like "{" and "}" 6 | homepage: https://github.com/juliangruber/balanced-match 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: | 11 | (MIT) 12 | 13 | Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | - sources: README.md 33 | text: |- 34 | (MIT) 35 | 36 | Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy of 39 | this software and associated documentation files (the "Software"), to deal in 40 | the Software without restriction, including without limitation the rights to 41 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 42 | of the Software, and to permit persons to whom the Software is furnished to do 43 | so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in all 46 | copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 53 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 54 | SOFTWARE. 55 | notices: [] 56 | -------------------------------------------------------------------------------- /.licenses/npm/brace-expansion.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: brace-expansion 3 | version: 1.1.11 4 | type: npm 5 | summary: Brace expansion as known from sh/bash 6 | homepage: https://github.com/juliangruber/brace-expansion 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | MIT License 12 | 13 | Copyright (c) 2013 Julian Gruber 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | - sources: README.md 33 | text: |- 34 | (MIT) 35 | 36 | Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy of 39 | this software and associated documentation files (the "Software"), to deal in 40 | the Software without restriction, including without limitation the rights to 41 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 42 | of the Software, and to permit persons to whom the Software is furnished to do 43 | so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in all 46 | copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 53 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 54 | SOFTWARE. 55 | notices: [] 56 | -------------------------------------------------------------------------------- /.licenses/npm/concat-map.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: concat-map 3 | version: 0.0.1 4 | type: npm 5 | summary: concatenative mapdashery 6 | homepage: https://github.com/substack/node-concat-map#readme 7 | license: other 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | This software is released under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of 14 | this software and associated documentation files (the "Software"), to deal in 15 | the Software without restriction, including without limitation the rights to 16 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | the Software, and to permit persons to whom the Software is furnished to do so, 18 | subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 25 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 26 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 27 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | - sources: README.markdown 30 | text: MIT 31 | notices: [] 32 | -------------------------------------------------------------------------------- /.licenses/npm/esprima.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: esprima 3 | version: 4.0.1 4 | type: npm 5 | summary: ECMAScript parsing infrastructure for multipurpose analysis 6 | homepage: http://esprima.org 7 | license: bsd-2-clause 8 | licenses: 9 | - sources: LICENSE.BSD 10 | text: | 11 | Copyright JS Foundation and other contributors, https://js.foundation/ 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 26 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | notices: [] 33 | -------------------------------------------------------------------------------- /.licenses/npm/js-yaml.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: js-yaml 3 | version: 3.14.0 4 | type: npm 5 | summary: YAML 1.2 parser and serializer 6 | homepage: https://github.com/nodeca/js-yaml 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | (The MIT License) 12 | 13 | Copyright (C) 2011-2015 by Vitaly Puzrin 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | notices: [] 33 | -------------------------------------------------------------------------------- /.licenses/npm/minimatch.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: minimatch 3 | version: 3.0.4 4 | type: npm 5 | summary: a glob matcher in javascript 6 | homepage: https://github.com/isaacs/minimatch#readme 7 | license: isc 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | The ISC License 12 | 13 | Copyright (c) Isaac Z. Schlueter and Contributors 14 | 15 | Permission to use, copy, modify, and/or distribute this software for any 16 | purpose with or without fee is hereby granted, provided that the above 17 | copyright notice and this permission notice appear in all copies. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 20 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 22 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 25 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 | notices: [] 27 | -------------------------------------------------------------------------------- /.licenses/npm/semver.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: semver 3 | version: 6.3.0 4 | type: npm 5 | summary: The semantic version parser used by npm. 6 | homepage: https://github.com/npm/node-semver#readme 7 | license: isc 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | The ISC License 12 | 13 | Copyright (c) Isaac Z. Schlueter and Contributors 14 | 15 | Permission to use, copy, modify, and/or distribute this software for any 16 | purpose with or without fee is hereby granted, provided that the above 17 | copyright notice and this permission notice appear in all copies. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 20 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 22 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 25 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 26 | notices: [] 27 | -------------------------------------------------------------------------------- /.licenses/npm/sprintf-js.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sprintf-js 3 | version: 1.0.3 4 | type: npm 5 | summary: JavaScript sprintf implementation 6 | homepage: https://github.com/alexei/sprintf.js#readme 7 | license: bsd-3-clause 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | Copyright (c) 2007-2014, Alexandru Marasteanu 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | * Neither the name of this software nor the names of its contributors may be 22 | used to endorse or promote products derived from this software without 23 | specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 29 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | - sources: README.md 36 | text: "**sprintf.js** is licensed under the terms of the 3-clause BSD license." 37 | notices: [] 38 | -------------------------------------------------------------------------------- /.licenses/npm/tunnel.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: tunnel 3 | version: 0.0.6 4 | type: npm 5 | summary: Node HTTP/HTTPS Agents for tunneling proxies 6 | homepage: https://github.com/koichik/node-tunnel/ 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | The MIT License (MIT) 12 | 13 | Copyright (c) 2012 Koichi Kobayashi 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | - sources: README.md 33 | text: Licensed under the [MIT](https://github.com/koichik/node-tunnel/blob/master/LICENSE) 34 | license. 35 | notices: [] 36 | -------------------------------------------------------------------------------- /.licenses/npm/uuid.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: uuid 3 | version: 3.4.0 4 | type: npm 5 | summary: RFC4122 (v1, v4, and v5) UUIDs 6 | homepage: https://github.com/uuidjs/uuid#readme 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: | 11 | The MIT License (MIT) 12 | 13 | Copyright (c) 2010-2016 Robert Kieffer and other contributors 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | notices: 33 | - sources: AUTHORS 34 | text: |- 35 | Robert Kieffer 36 | Christoph Tavan 37 | AJ ONeal 38 | Vincent Voyer 39 | Roman Shtylman 40 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '!(*test).{js,ts}': 'eslint --cache --fix', 3 | '!(*test).ts': () => ['ncc build', 'git add dist'], 4 | 'src/**/*.ts': () => 'tsc -p tsconfig.json', 5 | '*.{js,ts,json,md}': 'prettier --write' 6 | }; 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .out/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": false, 9 | "arrowParens": "avoid" 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 GitHub, Inc. and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # setup-haskell 2 | 3 | **Please note:** This repository is currently unmaintained by a team of developers at GitHub. The 4 | repository is here and you can use it as an example, or in Actions. However please be aware that 5 | we are not going to be updating issues or pull requests on this repository. 6 | 7 | **Maintained forks:** 8 | * [haskell/actions](https://github.com/haskell/actions) 9 | 10 | You could also fork this code and maintain it, if you do please let us know. 11 | 12 | To reflect this state we’ve marked this repository as Archived. 13 | 14 | If you are having an issue or question about GitHub Actions then please [contact customer support](https://help.github.com/en/articles/about-github-actions#contacting-support). 15 | 16 | If you have found a security issue [please submit it here](https://hackerone.com/github). 17 | 18 | --- 19 | 20 | [![GitHub Actions status](https://github.com/actions/setup-haskell/workflows/Main%20workflow/badge.svg)](https://github.com/actions/setup-haskell) 21 | 22 | This action sets up a Haskell environment for use in actions by: 23 | 24 | - optionally installing a version of [ghc](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/) and [cabal](https://www.haskell.org/cabal/) and adding to PATH. 25 | - optionally installing a version of [Stack](https://haskellstack.org) and adding to PATH. 26 | - setting the outputs of `ghc-path`, `cabal-path`, `stack-path`, and `cabal-store` when necessary. 27 | 28 | The GitHub runners come with [pre-installed versions of GHC and Cabal](https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners). Those will be used whenever possible. 29 | For all other versions, this action utilizes [`ppa:hvr/ghc`](https://launchpad.net/~hvr/+archive/ubuntu/ghc), [`ghcup`](https://gitlab.haskell.org/haskell/ghcup-hs), and [`chocolatey`](https://chocolatey.org/packages/ghc). 30 | 31 | ## Usage 32 | 33 | See [action.yml](action.yml) 34 | 35 | Minimal: 36 | 37 | ```yaml 38 | on: [push] 39 | name: build 40 | jobs: 41 | runhaskell: 42 | name: Hello World 43 | runs-on: ubuntu-latest # or macOS-latest, or windows-latest 44 | steps: 45 | - uses: actions/checkout@v2 46 | - uses: actions/setup-haskell@v1.1 47 | - run: runhaskell Hello.hs 48 | ``` 49 | 50 | Basic: 51 | 52 | ```yaml 53 | on: [push] 54 | name: build 55 | jobs: 56 | runhaskell: 57 | name: Hello World 58 | runs-on: ubuntu-latest # or macOS-latest, or windows-latest 59 | steps: 60 | - uses: actions/checkout@v2 61 | - uses: actions/setup-haskell@v1.1 62 | with: 63 | ghc-version: '8.8' # Resolves to the latest point release of GHC 8.8 64 | cabal-version: '3.0.0.0' # Exact version of Cabal 65 | - run: runhaskell Hello.hs 66 | ``` 67 | 68 | Basic with Stack: 69 | 70 | ```yaml 71 | on: [push] 72 | name: build 73 | jobs: 74 | runhaskell: 75 | name: Hello World 76 | runs-on: ubuntu-latest # or macOS-latest, or windows-latest 77 | steps: 78 | - uses: actions/checkout@v2 79 | - uses: actions/setup-haskell@v1.1 80 | with: 81 | ghc-version: '8.8.3' # Exact version of ghc to use 82 | # cabal-version: 'latest'. Omitted, but defalts to 'latest' 83 | enable-stack: true 84 | stack-version: 'latest' 85 | - run: runhaskell Hello.hs 86 | ``` 87 | 88 | Matrix Testing: 89 | 90 | ```yaml 91 | on: [push] 92 | name: build 93 | jobs: 94 | build: 95 | runs-on: ${{ matrix.os }} 96 | strategy: 97 | matrix: 98 | ghc: ['8.6.5', '8.8.3'] 99 | cabal: ['2.4.1.0', '3.0.0.0'] 100 | os: [ubuntu-latest, macOS-latest, windows-latest] 101 | exclude: 102 | # GHC 8.8+ only works with cabal v3+ 103 | - ghc: 8.8.3 104 | cabal: 2.4.1.0 105 | name: Haskell GHC ${{ matrix.ghc }} sample 106 | steps: 107 | - uses: actions/checkout@v2 108 | - name: Setup Haskell 109 | uses: actions/setup-haskell@v1.1 110 | with: 111 | ghc-version: ${{ matrix.ghc }} 112 | cabal-version: ${{ matrix.cabal }} 113 | - run: runhaskell Hello.hs 114 | ``` 115 | 116 | ## Inputs 117 | 118 | | Name | Required | Description | Type | Default | 119 | | ----------------- | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- | 120 | | `ghc-version` | | GHC version to use, ex. `latest` | string | latest | 121 | | `cabal-version` | | Cabal version to use, ex. `3.2` | string | latest | 122 | | `stack-version` | | Stack version to use, ex. `latest`. Stack will only be installed if enable-stack is set. | string | latest | 123 | | `enable-stack` | | If specified, will setup Stack. | "boolean" | false | 124 | | `stack-no-global` | | If specified, enable-stack must be set. Prevents installing GHC and Cabal globally | "boolean" | false | 125 | | `stack-setup-ghc` | | If specified, enable-stack must be set. Runs stack setup to install the specified GHC. (Note: setting this does _not_ imply `stack-no-global`) | "boolean" | false | 126 | 127 | ## Outputs 128 | 129 | | Name | Description | Type | 130 | | ------------- | -------------------------------------------- | ------ | 131 | | `ghc-path` | The path of the ghc executable _directory_ | string | 132 | | `cabal-path` | The path of the cabal executable _directory_ | string | 133 | | `stack-path` | The path of the stack executable _directory_ | string | 134 | | `cabal-store` | The path to the cabal store | string | 135 | | `ghc-exe` | The path of the ghc _executable_ | string | 136 | | `cabal-exe` | The path of the cabal _executable_ | string | 137 | | `stack-exe` | The path of the stack _executable_ | string | 138 | 139 | ## Version Support 140 | 141 | **GHC:** 142 | 143 | - `latest` (default, recommended) 144 | - `8.10.1` `8.10` 145 | - `8.8.3` `8.8` 146 | - `8.8.2` 147 | - `8.8.1` 148 | - `8.6.5` `8.6` 149 | - `8.6.4` 150 | - `8.6.3` 151 | - `8.6.2` 152 | - `8.6.1` 153 | - `8.4.4` `8.4` 154 | - `8.4.3` 155 | - `8.4.2` 156 | - `8.4.1` 157 | - `8.2.2` `8.2` 158 | - `8.0.2` `8.0` 159 | - `7.10.3` `7.10` 160 | 161 | Suggestion: Try to support the three latest major versions of GHC. 162 | 163 | **Cabal:** 164 | 165 | - `latest` (default, recommended) 166 | - `3.2.0.0` `3.2` 167 | - `3.0.0.0` `3.0` 168 | - `2.4.1.0` `2.4` 169 | - `2.4.0.0` 170 | - `2.2.0.0` `2.2` 171 | 172 | Recommendation: Use the latest available version if possible. 173 | 174 | **Stack:** 175 | 176 | - `latest` (recommended) -- follows the latest release automatically. 177 | - `2.3.1` `2.3` 178 | - `2.1.3` `2.1` 179 | - `2.1.1` 180 | - `1.9.3.1` `1.9` 181 | - `1.9.1.1` 182 | - `1.7.1` `1.7` 183 | - `1.6.5` `1.6` 184 | - `1.6.3.1` 185 | - `1.6.1.1` 186 | - `1.5.1` `1.5` 187 | - `1.5.0` 188 | - `1.4.0` `1.4` 189 | - `1.3.2` `1.3` 190 | - `1.3.0` 191 | - `1.2.0` `1.2` 192 | 193 | Recommendation: Use the latest available version if possible. 194 | 195 | The full list of available versions of GHC, Cabal, and Stack are as follows: 196 | 197 | - [Linux/macOS - Cabal and GHC](https://www.haskell.org/ghc/download.html) 198 | - [Windows - Cabal](https://chocolatey.org/packages/cabal#versionhistory). 199 | - [Windows - GHC](https://chocolatey.org/packages/ghc#versionhistory) 200 | - [Linux/macOS/Windows - Stack](https://github.com/commercialhaskell/stack/tags) 201 | 202 | Note: There are _technically_ some descrepencies here. For example, "8.10.1-alpha1" will work for a ghc version for windows but not for Linux and macOS. For your sanity, I suggest sticking with the version lists above which are supported across all three operating systems. 203 | 204 | ## License 205 | 206 | The scripts and documentation in this project are released under the [MIT License](LICENSE). 207 | 208 | ## Contributions 209 | 210 | Contributions are welcome! See the [Contributor's Guide](docs/contributors.md). 211 | -------------------------------------------------------------------------------- /__tests__/find-haskell.test.ts: -------------------------------------------------------------------------------- 1 | import {getOpts, getDefaults, Tool} from '../src/opts'; 2 | import {getInput} from '@actions/core'; 3 | import * as supported_versions from '../src/versions.json'; 4 | 5 | const def = getDefaults(); 6 | const latestVersions = { 7 | ghc: supported_versions.ghc[0], 8 | cabal: supported_versions.cabal[0], 9 | stack: supported_versions.stack[0] 10 | }; 11 | 12 | const mkName = (s: string): string => 13 | `INPUT_${s.replace(/ /g, '_').toUpperCase()}`; 14 | 15 | const setupEnv = (o: Record): void => 16 | Object.entries(o).forEach(([k, v]) => v && (process.env[mkName(k)] = `${v}`)); 17 | 18 | const forAll = (fn: (t: Tool) => any) => 19 | (['ghc', 'cabal', 'stack'] as const).forEach(fn); 20 | 21 | describe('actions/setup-haskell', () => { 22 | const OLD_ENV = process.env; 23 | 24 | beforeEach(() => { 25 | jest.resetModules(); 26 | process.env = {...OLD_ENV}; 27 | delete process.env.NODE_ENV; 28 | }); 29 | 30 | afterEach(() => (process.env = OLD_ENV)); 31 | 32 | it('Parses action.yml to get correct default versions', () => { 33 | forAll(t => expect(def[t].version).toBe(latestVersions[t])); 34 | }); 35 | 36 | it('Supported versions are parsed from JSON correctly', () => 37 | forAll(t => expect(def[t].supported).toBe(supported_versions[t]))); 38 | 39 | it('[meta] Setup Env works', () => { 40 | setupEnv({input: 'value'}); 41 | const i = getInput('input'); 42 | expect(i).toEqual('value'); 43 | }); 44 | 45 | it('getOpts grabs defaults correctly from environment', () => { 46 | setupEnv({}); 47 | const options = getOpts(def); 48 | forAll(t => expect(options[t].raw).toBe(def[t].version)); 49 | }); 50 | 51 | it('Versions resolve correctly', () => { 52 | const v = {ghc: '8.6.5', cabal: '2.4.1.0', stack: '2.1.3'}; 53 | setupEnv({ 54 | 'stack-version': '2.1', 55 | 'ghc-version': '8.6', 56 | 'cabal-version': '2.4' 57 | }); 58 | const options = getOpts(def); 59 | forAll(t => expect(options[t].resolved).toBe(v[t])); 60 | }); 61 | 62 | it('"latest" Versions resolve correctly', () => { 63 | setupEnv({ 64 | 'stack-version': 'latest', 65 | 'ghc-version': 'latest', 66 | 'cabal-version': 'latest' 67 | }); 68 | const options = getOpts(def); 69 | forAll(t => expect(options[t].resolved).toBe(latestVersions[t])); 70 | }); 71 | 72 | it('Enabling stack does not disable GHC or Cabal', () => { 73 | setupEnv({'enable-stack': 'true'}); 74 | const {ghc, cabal, stack} = getOpts(def); 75 | expect({ 76 | ghc: ghc.enable, 77 | stack: stack.enable, 78 | cabal: cabal.enable 79 | }).toStrictEqual({ghc: true, cabal: true, stack: true}); 80 | }); 81 | 82 | it('Enabling stack-no-global disables GHC and Cabal', () => { 83 | setupEnv({'enable-stack': 'true', 'stack-no-global': 'true'}); 84 | const {ghc, cabal, stack} = getOpts(def); 85 | expect({ 86 | ghc: ghc.enable, 87 | cabal: cabal.enable, 88 | stack: stack.enable 89 | }).toStrictEqual({ghc: false, cabal: false, stack: true}); 90 | }); 91 | 92 | it('Enabling stack-no-global without setting enable-stack errors', () => { 93 | setupEnv({'stack-no-global': 'true'}); 94 | expect(() => getOpts(def)).toThrow(); 95 | }); 96 | 97 | it('Enabling stack-setup-ghc without setting enable-stack errors', () => { 98 | setupEnv({'stack-setup-ghc': 'true'}); 99 | expect(() => getOpts(def)).toThrow(); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /__tests__/hello.hs: -------------------------------------------------------------------------------- 1 | module Hello where 2 | 3 | main = putStrLn "Hello, World!" 4 | -------------------------------------------------------------------------------- /__tests__/project/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main :: IO () 4 | main = putStrLn "Hello, Haskell!" 5 | -------------------------------------------------------------------------------- /__tests__/project/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /__tests__/project/project.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: >=1.10 2 | name: project 3 | version: 0.1.0.0 4 | build-type: Simple 5 | 6 | executable project 7 | main-is: Main.hs 8 | build-depends: base 9 | default-language: Haskell2010 10 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Haskell' 2 | description: 'Set up a specific version of GHC and Cabal and add the command-line tools to the PATH' 3 | author: 'GitHub' 4 | inputs: 5 | ghc-version: 6 | required: false 7 | description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version.' 8 | default: 'latest' 9 | cabal-version: 10 | required: false 11 | description: 'Version of Cabal to use. If set to "latest", it will always get the latest stable version.' 12 | default: 'latest' 13 | stack-version: 14 | required: false 15 | description: 'Version of Stack to use. If set to "latest", it will always get the latest stable version.' 16 | default: 'latest' 17 | enable-stack: 18 | required: false 19 | description: 'If specified, will setup Stack' 20 | stack-no-global: 21 | required: false 22 | description: 'If specified, enable-stack must be set. Prevents installing GHC and Cabal globally' 23 | stack-setup-ghc: 24 | required: false 25 | description: 'If specified, enable-stack must be set. Will run stack setup to install the specified GHC' 26 | outputs: 27 | ghc-path: 28 | description: 'The path of the ghc executable _directory_' 29 | cabal-path: 30 | description: 'The path of the cabal executable _directory_' 31 | stack-path: 32 | description: 'The path of the stack executable _directory_' 33 | cabal-store: 34 | description: 'The path to the cabal store' 35 | ghc-exe: 36 | description: 'The path of the ghc _executable_' 37 | cabal-exe: 38 | description: 'The path of the cabal _executable_' 39 | stack-exe: 40 | description: 'The path of the stack _executable_' 41 | runs: 42 | using: 'node12' 43 | main: 'dist/index.js' 44 | -------------------------------------------------------------------------------- /dist/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Haskell' 2 | description: 'Set up a specific version of GHC and Cabal and add the command-line tools to the PATH' 3 | author: 'GitHub' 4 | inputs: 5 | ghc-version: 6 | required: false 7 | description: 'Version of GHC to use. If set to "latest", it will always get the latest stable version.' 8 | default: 'latest' 9 | cabal-version: 10 | required: false 11 | description: 'Version of Cabal to use. If set to "latest", it will always get the latest stable version.' 12 | default: 'latest' 13 | stack-version: 14 | required: false 15 | description: 'Version of Stack to use. If set to "latest", it will always get the latest stable version.' 16 | default: 'latest' 17 | enable-stack: 18 | required: false 19 | description: 'If specified, will setup Stack' 20 | stack-no-global: 21 | required: false 22 | description: 'If specified, enable-stack must be set. Prevents installing GHC and Cabal globally' 23 | stack-setup-ghc: 24 | required: false 25 | description: 'If specified, enable-stack must be set. Will run stack setup to install the specified GHC' 26 | outputs: 27 | ghc-path: 28 | description: 'The path of the ghc executable _directory_' 29 | cabal-path: 30 | description: 'The path of the cabal executable _directory_' 31 | stack-path: 32 | description: 'The path of the stack executable _directory_' 33 | cabal-store: 34 | description: 'The path to the cabal store' 35 | ghc-exe: 36 | description: 'The path of the ghc _executable_' 37 | cabal-exe: 38 | description: 'The path of the cabal _executable_' 39 | stack-exe: 40 | description: 'The path of the stack _executable_' 41 | runs: 42 | using: 'node12' 43 | main: 'dist/index.js' 44 | -------------------------------------------------------------------------------- /docs/contributors.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | ### Checkin 4 | 5 | - Do checkin source (src) 6 | - Do checkin build output (dist) 7 | 8 | ### Dependencies 9 | 10 | In order to make sure that the ts files are always transpiled correctly, we run [Husky](https://github.com/typicode/husky) before each commit. 11 | This step ensures that formatting rules are followed and that the typescript code has been transpiled correctly. To make sure Husky runs correctly, please use the following workflow: 12 | 13 | ```sh 14 | npm install # installs all dependencies including Husky 15 | git add abc.ext # Add the files you've changed. This should include files in src and dist (see above) 16 | git commit -m "Informative commit message" # Commit. This will run Husky 17 | ``` 18 | 19 | During the commit step, Husky will take care of formatting all files with [Prettier](https://github.com/prettier/prettier). It will also bundle the code into a single `dist/index.js` file. 20 | Finally, it will make sure these changes are appropriately included in your commit--no further work is needed. 21 | 22 | ## Versions 23 | 24 | Cabal does not follow SemVer and Stack has both SemVer compatible version numbers as well as PVP-style versions; due to this, support for "resolving" a version like `X.X` into the latest `X.X.Y` or `X.X.Y.Y` version is tricky. 25 | To avoid complications, all recognized versions of GHC, Cabal, and Stack are in `src/versions.json`; these versions are supported across all three operating systems. 26 | When a new release of GHC, Cabal, or Stack comes out, the `src/versions.json` file will need to be updated accordingly. 27 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | export interface ProcessEnv { 3 | /** 4 | * The path to the GitHub home directory used to store user data. 5 | * 6 | * Example: /github/home. 7 | */ 8 | HOME: string; 9 | 10 | /** The name of the workflow. */ 11 | GITHUB_WORKFLOW: string; 12 | 13 | /** 14 | * A unique number for each run within a repository. This number does not 15 | * change if you re-run the workflow run. 16 | */ 17 | GITHUB_RUN_ID: string; 18 | 19 | /** 20 | * A unique number for each run of a particular workflow in a repository. 21 | * This number begins at 1 for the workflow's first run, and increments with 22 | * each new run. This number does not change if you re-run the workflow run. 23 | * */ 24 | GITHUB_RUN_NUMBER: string; 25 | 26 | /** The unique identifier (id) of the action. */ 27 | GITHUB_ACTION: string; 28 | 29 | /** 30 | * Always set to true when GitHub Actions is running the workflow. You can 31 | * use this variable to differentiate when tests are being run locally or 32 | * by GitHub Actions. 33 | */ 34 | GITHUB_ACTIONS: string; 35 | 36 | /** 37 | * The name of the person or app that initiated the workflow. 38 | * 39 | * Example: octocat. 40 | */ 41 | GITHUB_ACTOR: string; 42 | 43 | /** The owner and repository name. For example, octocat/Hello-World. */ 44 | GITHUB_REPOSITORY: string; 45 | 46 | /** The name of the webhook event that triggered the workflow. */ 47 | GITHUB_EVENT_NAME: string; 48 | 49 | /** 50 | * The path of the file with the complete webhook event payload. 51 | * 52 | * Example: /github/workflow/event.json. 53 | */ 54 | GITHUB_EVENT_PATH: string; 55 | 56 | /** 57 | * The GitHub workspace directory path. The workspace directory contains a 58 | * subdirectory with a copy of your repository if your workflow uses the 59 | * actions/checkout action. If you don't use the actions/checkout action, 60 | * the directory will be empty. 61 | * 62 | * Example: /home/runner/work/my-repo-name/my-repo-name. 63 | */ 64 | GITHUB_WORKSPACE: string; 65 | 66 | /** 67 | * The commit SHA that triggered the workflow. 68 | * 69 | * Example: ffac537e6cbbf934b08745a378932722df287a53. 70 | */ 71 | GITHUB_SHA: string; 72 | 73 | /** 74 | * The branch or tag ref that triggered the workflow. If neither a branch 75 | * or tag is available for the event type, the variable will not exist. 76 | * 77 | * Example: refs/heads/feature-branch-1. 78 | */ 79 | GITHUB_REF: string; 80 | 81 | /** Only set for forked repositories. The branch of the head repository. */ 82 | GITHUB_HEAD_REF: string; 83 | 84 | /** Only set for forked repositories. The branch of the base repository. */ 85 | GITHUB_BASE_REF: string; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: {'^.+\\.ts$': 'ts-jest'}, 8 | verbose: true 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setup-haskell", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "setup haskell action", 6 | "main": "src/setup-haskell.ts", 7 | "scripts": { 8 | "test": "jest" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/actions/setup-haskell.git" 13 | }, 14 | "keywords": [ 15 | "actions", 16 | "haskell", 17 | "ghc", 18 | "cabal", 19 | "setup" 20 | ], 21 | "author": "GitHub", 22 | "license": "MIT", 23 | "dependencies": { 24 | "@actions/core": "^1.2.4", 25 | "@actions/exec": "^1.0.4", 26 | "@actions/glob": "^0.1.0", 27 | "@actions/io": "^1.0.2", 28 | "@actions/tool-cache": "^1.5.5", 29 | "js-yaml": "^3.14.0" 30 | }, 31 | "devDependencies": { 32 | "@types/jest": "^25.2.3", 33 | "@types/js-yaml": "^3.12.4", 34 | "@types/node": "^14.0.11", 35 | "@typescript-eslint/parser": "^3.1.0", 36 | "@typescript-eslint/eslint-plugin": "^3.1.0", 37 | "@zeit/ncc": "^0.22.3", 38 | "eslint": "^7.1.0", 39 | "eslint-plugin-github": "^4.0.1", 40 | "eslint-plugin-jest": "^23.13.2", 41 | "husky": "^4.2.5", 42 | "jest": "^26.0.1", 43 | "jest-circus": "^26.0.1", 44 | "lint-staged": "^10.2.9", 45 | "prettier": "^2.0.5", 46 | "ts-jest": "^26.1.0", 47 | "typescript": "^3.9.5" 48 | }, 49 | "husky": { 50 | "hooks": { 51 | "pre-commit": "lint-staged", 52 | "pre-push": "npm test" 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/installer.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import {exec} from '@actions/exec'; 3 | import {which} from '@actions/io'; 4 | import {create as glob} from '@actions/glob'; 5 | import * as tc from '@actions/tool-cache'; 6 | import {promises as fs} from 'fs'; 7 | import {join} from 'path'; 8 | import type {OS, Tool} from './opts'; 9 | 10 | function failed(tool: Tool, version: string): void { 11 | throw new Error(`All install methods for ${tool} ${version} failed`); 12 | } 13 | 14 | async function success( 15 | tool: Tool, 16 | version: string, 17 | path: string 18 | ): Promise { 19 | core.addPath(path); 20 | core.setOutput(`${tool}-path`, path); 21 | core.setOutput(`${tool}-exe`, await which(tool)); 22 | core.info( 23 | `Found ${tool} ${version} in cache at path ${path}. Setup successful.` 24 | ); 25 | return true; 26 | } 27 | 28 | function warn(tool: Tool, version: string): void { 29 | const policy = { 30 | cabal: `the two latest major releases of ${tool} are commonly supported.`, 31 | ghc: `the three latest major releases of ${tool} are commonly supported.`, 32 | stack: `the latest release of ${tool} is commonly supported.` 33 | }[tool]; 34 | 35 | core.warning( 36 | `${tool} ${version} was not found in the cache. It will be downloaded.\n` + 37 | `If this is unexpected, please check if version ${version} is pre-installed.\n` + 38 | `The list of pre-installed versions is available here: https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners\n` + 39 | `The above list follows a common haskell convention that ${policy}\n` + 40 | 'If the list is outdated, please file an issue here: https://github.com/actions/virtual-environments\n' + 41 | 'by using the appropriate tool request template: https://github.com/actions/virtual-environments/issues/new/choose' 42 | ); 43 | } 44 | 45 | async function isInstalled( 46 | tool: Tool, 47 | version: string, 48 | os: OS 49 | ): Promise { 50 | const toolPath = tc.find(tool, version); 51 | if (toolPath) return success(tool, version, toolPath); 52 | 53 | const ghcupPath = `${process.env.HOME}/.ghcup${ 54 | tool === 'ghc' ? `/ghc/${version}` : '' 55 | }/bin`; 56 | const v = tool === 'cabal' ? version.slice(0, 3) : version; 57 | const aptPath = `/opt/${tool}/${v}/bin`; 58 | 59 | const chocoPath = getChocoPath(tool, version); 60 | 61 | const locations = { 62 | stack: [], // Always installed into the tool cache 63 | cabal: { 64 | win32: [chocoPath], 65 | linux: [aptPath], 66 | darwin: [] 67 | }[os], 68 | ghc: { 69 | win32: [chocoPath], 70 | linux: [aptPath, ghcupPath], 71 | darwin: [ghcupPath] 72 | }[os] 73 | }; 74 | 75 | for (const p of locations[tool]) { 76 | const installedPath = await fs 77 | .access(p) 78 | .then(() => p) 79 | .catch(() => undefined); 80 | 81 | if (installedPath) { 82 | // Make sure that the correct ghc is used, even if ghcup has set a 83 | // default prior to this action being ran. 84 | if (tool === 'ghc' && installedPath === ghcupPath) 85 | await exec(await ghcupBin(os), ['set', version]); 86 | 87 | return success(tool, version, installedPath); 88 | } 89 | } 90 | 91 | if (tool === 'cabal' && os !== 'win32') { 92 | const installedPath = await fs 93 | .access(`${ghcupPath}/cabal`) 94 | .then(() => ghcupPath) 95 | .catch(() => undefined); 96 | 97 | if (installedPath) return success(tool, version, installedPath); 98 | } 99 | 100 | return false; 101 | } 102 | 103 | export async function installTool( 104 | tool: Tool, 105 | version: string, 106 | os: OS 107 | ): Promise { 108 | if (await isInstalled(tool, version, os)) return; 109 | warn(tool, version); 110 | 111 | if (tool === 'stack') { 112 | await stack(version, os); 113 | if (await isInstalled(tool, version, os)) return; 114 | return failed(tool, version); 115 | } 116 | 117 | switch (os) { 118 | case 'linux': 119 | await apt(tool, version); 120 | if (await isInstalled(tool, version, os)) return; 121 | await ghcup(tool, version, os); 122 | break; 123 | case 'win32': 124 | await choco(tool, version); 125 | break; 126 | case 'darwin': 127 | await ghcup(tool, version, os); 128 | break; 129 | } 130 | 131 | if (await isInstalled(tool, version, os)) return; 132 | return failed(tool, version); 133 | } 134 | 135 | async function stack(version: string, os: OS): Promise { 136 | core.info(`Attempting to install stack ${version}`); 137 | const build = { 138 | linux: `linux-x86_64${version >= '2.3.1' ? '' : '-static'}`, 139 | darwin: 'osx-x86_64', 140 | win32: 'windows-x86_64' 141 | }[os]; 142 | 143 | const url = `https://github.com/commercialhaskell/stack/releases/download/v${version}/stack-${version}-${build}.tar.gz`; 144 | const p = await tc.downloadTool(`${url}`).then(tc.extractTar); 145 | const [stackPath] = await glob(`${p}/stack*`, { 146 | implicitDescendants: false 147 | }).then(async g => g.glob()); 148 | await tc.cacheDir(stackPath, 'stack', version); 149 | 150 | if (os === 'win32') core.exportVariable('STACK_ROOT', 'C:\\sr'); 151 | } 152 | 153 | async function apt(tool: Tool, version: string): Promise { 154 | const toolName = tool === 'ghc' ? 'ghc' : 'cabal-install'; 155 | const v = tool === 'cabal' ? version.slice(0, 3) : version; 156 | core.info(`Attempting to install ${toolName} ${v} using apt-get`); 157 | // Ignore the return code so we can fall back to ghcup 158 | await exec(`sudo -- sh -c "apt-get -y install ${toolName}-${v}"`, undefined, { 159 | ignoreReturnCode: true 160 | }); 161 | } 162 | 163 | async function choco(tool: Tool, version: string): Promise { 164 | core.info(`Attempting to install ${tool} ${version} using chocolatey`); 165 | // Choco tries to invoke `add-path` command on earlier versions of ghc, which has been deprecated and fails the step, so disable command execution during this. 166 | console.log('::stop-commands::SetupHaskellStopCommands'); 167 | await exec( 168 | 'powershell', 169 | [ 170 | 'choco', 171 | 'install', 172 | tool, 173 | '--version', 174 | version, 175 | '-m', 176 | '--no-progress', 177 | '-r' 178 | ], 179 | { 180 | ignoreReturnCode: true 181 | } 182 | ); 183 | console.log('::SetupHaskellStopCommands::'); // Re-enable command execution 184 | // Add GHC to path automatically because it does not add until the end of the step and we check the path. 185 | if (tool == 'ghc') { 186 | core.addPath(getChocoPath(tool, version)); 187 | } 188 | } 189 | 190 | async function ghcupBin(os: OS): Promise { 191 | const v = '0.1.8'; 192 | const cachedBin = tc.find('ghcup', v); 193 | if (cachedBin) return join(cachedBin, 'ghcup'); 194 | 195 | const bin = await tc.downloadTool( 196 | `https://downloads.haskell.org/ghcup/${v}/x86_64-${ 197 | os === 'darwin' ? 'apple-darwin' : 'linux' 198 | }-ghcup-${v}` 199 | ); 200 | await fs.chmod(bin, 0o755); 201 | return join(await tc.cacheFile(bin, 'ghcup', 'ghcup', v), 'ghcup'); 202 | } 203 | 204 | async function ghcup(tool: Tool, version: string, os: OS): Promise { 205 | core.info(`Attempting to install ${tool} ${version} using ghcup`); 206 | const bin = await ghcupBin(os); 207 | const returnCode = await exec( 208 | bin, 209 | [tool === 'ghc' ? 'install' : 'install-cabal', version], 210 | { 211 | ignoreReturnCode: true 212 | } 213 | ); 214 | if (returnCode === 0 && tool === 'ghc') await exec(bin, ['set', version]); 215 | } 216 | 217 | function getChocoPath(tool: Tool, version: string): string { 218 | // Manually add the path because it won't happen until the end of the step normally 219 | const pathArray = version.split('.'); 220 | const pathVersion = 221 | pathArray.length > 3 222 | ? pathArray.slice(0, pathArray.length - 1).join('.') 223 | : pathArray.join('.'); 224 | const chocoPath = join( 225 | `${process.env.ChocolateyInstall}`, 226 | 'lib', 227 | `${tool}.${version}`, 228 | 'tools', 229 | tool === 'ghc' ? `${tool}-${pathVersion}` : `${tool}-${version}`, // choco trims the ghc version here 230 | tool === 'ghc' ? 'bin' : '' 231 | ); 232 | return chocoPath; 233 | } 234 | -------------------------------------------------------------------------------- /src/opts.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import {readFileSync} from 'fs'; 3 | import {safeLoad} from 'js-yaml'; 4 | import {join} from 'path'; 5 | import * as supported_versions from './versions.json'; 6 | 7 | export type OS = 'linux' | 'darwin' | 'win32'; 8 | export type Tool = 'cabal' | 'ghc' | 'stack'; 9 | 10 | export interface ProgramOpt { 11 | enable: boolean; 12 | raw: string; 13 | resolved: string; 14 | } 15 | 16 | export interface Options { 17 | ghc: ProgramOpt; 18 | cabal: ProgramOpt; 19 | stack: ProgramOpt & {setup: boolean}; 20 | } 21 | 22 | type Version = {version: string; supported: string[]}; 23 | export type Defaults = Record; 24 | 25 | export function getDefaults(): Defaults { 26 | const inpts = safeLoad( 27 | readFileSync(join(__dirname, '..', 'action.yml'), 'utf8') 28 | ).inputs; 29 | 30 | const mkVersion = (v: string, vs: string[]): Version => ({ 31 | version: resolve(inpts[v].default, vs), 32 | supported: vs 33 | }); 34 | 35 | return { 36 | ghc: mkVersion('ghc-version', supported_versions.ghc), 37 | cabal: mkVersion('cabal-version', supported_versions.cabal), 38 | stack: mkVersion('stack-version', supported_versions.stack) 39 | }; 40 | } 41 | 42 | function resolve(version: string, supported: string[]): string { 43 | return version === 'latest' 44 | ? supported[0] 45 | : supported.find(v => v.startsWith(version)) ?? version; 46 | } 47 | 48 | export function getOpts({ghc, cabal, stack}: Defaults): Options { 49 | const stackNoGlobal = core.getInput('stack-no-global') !== ''; 50 | const stackSetupGhc = core.getInput('stack-setup-ghc') !== ''; 51 | const stackEnable = core.getInput('enable-stack') !== ''; 52 | const verInpt = { 53 | ghc: core.getInput('ghc-version') || ghc.version, 54 | cabal: core.getInput('cabal-version') || cabal.version, 55 | stack: core.getInput('stack-version') || stack.version 56 | }; 57 | 58 | const errors = []; 59 | if (stackNoGlobal && !stackEnable) { 60 | errors.push('enable-stack is required if stack-no-global is set'); 61 | } 62 | 63 | if (stackSetupGhc && !stackEnable) { 64 | errors.push('enable-stack is required if stack-setup-ghc is set'); 65 | } 66 | 67 | if (errors.length > 0) { 68 | throw new Error(errors.join('\n')); 69 | } 70 | 71 | const opts: Options = { 72 | ghc: { 73 | raw: verInpt.ghc, 74 | resolved: resolve(verInpt.ghc, ghc.supported), 75 | enable: !stackNoGlobal 76 | }, 77 | cabal: { 78 | raw: verInpt.cabal, 79 | resolved: resolve(verInpt.cabal, cabal.supported), 80 | enable: !stackNoGlobal 81 | }, 82 | stack: { 83 | raw: verInpt.stack, 84 | resolved: resolve(verInpt.stack, stack.supported), 85 | enable: stackEnable, 86 | setup: core.getInput('stack-setup-ghc') !== '' 87 | } 88 | }; 89 | 90 | // eslint-disable-next-line github/array-foreach 91 | Object.values(opts) 92 | .filter(t => t.enable && t.raw !== t.resolved) 93 | .forEach(t => core.info(`Resolved ${t.raw} to ${t.resolved}`)); 94 | 95 | core.debug(`Options are: ${JSON.stringify(opts)}`); 96 | return opts; 97 | } 98 | -------------------------------------------------------------------------------- /src/setup-haskell.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as fs from 'fs'; 3 | import {getOpts, getDefaults, Tool} from './opts'; 4 | import {installTool} from './installer'; 5 | import type {OS} from './opts'; 6 | import {exec} from '@actions/exec'; 7 | 8 | async function cabalConfig(): Promise { 9 | let out = Buffer.from(''); 10 | const append = (b: Buffer): Buffer => (out = Buffer.concat([out, b])); 11 | await exec('cabal', ['--help'], { 12 | silent: true, 13 | listeners: {stdout: append, stderr: append} 14 | }); 15 | return out.toString().trim().split('\n').slice(-1)[0].trim(); 16 | } 17 | 18 | (async () => { 19 | try { 20 | core.info('Preparing to setup a Haskell environment'); 21 | const opts = getOpts(getDefaults()); 22 | 23 | for (const [t, {resolved}] of Object.entries(opts).filter(o => o[1].enable)) 24 | await core.group(`Installing ${t} version ${resolved}`, async () => 25 | installTool(t as Tool, resolved, process.platform as OS) 26 | ); 27 | 28 | if (opts.stack.setup) 29 | await core.group('Pre-installing GHC with stack', async () => 30 | exec('stack', ['setup', opts.ghc.resolved]) 31 | ); 32 | 33 | if (opts.cabal.enable) 34 | await core.group('Setting up cabal', async () => { 35 | await exec('cabal', ['user-config', 'update'], {silent: true}); 36 | const configFile = await cabalConfig(); 37 | 38 | if (process.platform === 'win32') { 39 | fs.appendFileSync(configFile, 'store-dir: C:\\sr\n'); 40 | core.setOutput('cabal-store', 'C:\\sr'); 41 | } else { 42 | core.setOutput('cabal-store', `${process.env.HOME}/.cabal/store`); 43 | } 44 | 45 | await exec('cabal user-config update'); 46 | if (!opts.stack.enable) await exec('cabal update'); 47 | }); 48 | } catch (error) { 49 | core.setFailed(error.message); 50 | } 51 | })(); 52 | -------------------------------------------------------------------------------- /src/versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "ghc": [ 3 | "8.10.2", 4 | "8.10.1", 5 | "8.8.4", 6 | "8.8.3", 7 | "8.8.2", 8 | "8.8.1", 9 | "8.6.5", 10 | "8.6.4", 11 | "8.6.3", 12 | "8.6.2", 13 | "8.6.1", 14 | "8.4.4", 15 | "8.4.3", 16 | "8.4.2", 17 | "8.4.1", 18 | "8.2.2", 19 | "8.0.2", 20 | "7.10.3" 21 | ], 22 | "cabal": ["3.2.0.0", "3.0.0.0", "2.4.1.0", "2.4.0.0", "2.2.0.0"], 23 | "stack": [ 24 | "2.3.1", 25 | "2.1.3", 26 | "2.1.1", 27 | "1.9.3", 28 | "1.9.1", 29 | "1.7.1", 30 | "1.6.5", 31 | "1.6.3", 32 | "1.6.1", 33 | "1.5.1", 34 | "1.5.0", 35 | "1.4.0", 36 | "1.3.2", 37 | "1.3.0", 38 | "1.2.0" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "lib": [ 5 | "es2019", 6 | "es2020.bigint", 7 | "es2020.string", 8 | "es2020.symbol.wellknown" 9 | ], 10 | "module": "commonjs", 11 | "outDir": ".out", 12 | "tsBuildInfoFile": ".out/tsbuildinfo", 13 | "incremental": true, 14 | "rootDir": "./src", 15 | "strict": true, 16 | "noImplicitAny": true, 17 | "esModuleInterop": true, 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true 20 | }, 21 | "exclude": ["node_modules", "**/*.test.ts"] 22 | } 23 | --------------------------------------------------------------------------------