Skip to content

Build and utilize pre-compiled binaries #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions .github/bin/build-binaries-matrix
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env ruby
require "json"

RELEASE_NAME = "Binaries"

EXISTING_ASSETS = JSON.parse(`
gh --repo freckle/weeder-action release view #{RELEASE_NAME} --json assets |
jq '.assets | map(.name)'
`)

GHCs = %W[
9.2.5
9.2.4
9.2.3
9.2.2
9.0.2
9.0.1
8.10.7
8.10.6
8.10.5
8.10.4
8.10.3
8.10.2
8.10.1
8.8.4
8.8.3
8.8.2
8.8.1
]
Comment on lines +11 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side quest, would it make sense to contribute this matrix to weeder itself and pull binaries from that project?

https://github.com/ocharles/weeder/releases

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocharles is using nix, which makes binary caching easy, but I'm not sure the current state of multi GHC builds in that ecosystem.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was indeed surprised when I found they weren't there. It's possible needing to have a binary built against the GHC of your project was enough complexity that they punted -- or maybe there's an Actual Reason they'd not want it. I'll probably open an Issue to ask at some point.


Asset = Struct.new(:ghc, :os) do
def name
"weeder-#{ghc}-#{os}-x64.#{os_attributes.fetch(:ext)}"
end

def include
{ asset: name, ghc: ghc, release: RELEASE_NAME }.
merge(os_attributes).
merge(version_attributes)
end

def os_attributes
case os
when "linux"
{ runner: "ubuntu-latest", ext: "tar.gz", zip: "tar -czf" }
when "darwin"
{ runner: "macOS-latest", ext: "tar.gz", zip: "tar -czf" }
when "win32"
{ runner: "windows-latest", ext: "zip", zip: "zip" }
else
raise "Unexpected OS: #{os}, must be linux|darwin|win32"
end
end

def version_attributes
case ghc
when /9\.2\..*/
{
version: "2.4.0",
resolver: "lts-20.3",
"extra-deps": ""
}
when /9\.0\..*/
{
version: "2.3.1",
resolver: "lts-19.33",
"extra-deps": ""
}
when /8\.10\..*/
{
version: "2.2.0",
resolver: "lts-18.28",
"extra-deps": [
"dhall-1.40.2",
"generic-lens-2.2.1.0",
"generic-lens-core-2.2.1.0"
].join(",")
}
when /8\.8\..*/
{
version: "2.2.0",
resolver: "lts-16.31",
"extra-deps": [
"dhall-1.40.2",
"generic-lens-2.2.1.0",
"generic-lens-core-2.2.1.0",
"base16-bytestring-1.0.2.0",
"prettyprinter-1.7.1",
"repline-0.4.2.0",
"haskeline-0.8.2"
].join(",")
}
end
end

def needed?
!EXISTING_ASSETS.include?(name)
end
end

def generate_matrix
assets = %W[ linux darwin ].
flat_map { |os| GHCs.map { |ghc| Asset.new(ghc, os) } }.
filter(&:needed?)

if assets.empty?
{
asset: ["none"],
include: [{
asset: "none",
runner: "ubuntu-latest"
}]
}
else
{
asset: assets.map(&:name),
include: assets.map(&:include)
}
end
end

puts JSON.dump(generate_matrix)
55 changes: 55 additions & 0 deletions .github/workflows/binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Binaries

on:
pull_request:

jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- id: generate
run: |
cat >>"$GITHUB_OUTPUT" <<EOM
matrix<<EOJSON
$(./.github/bin/build-binaries-matrix)
EOJSON
EOM
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
outputs:
matrix: ${{ steps.generate.outputs.matrix }}

binaries:
needs: generate

strategy:
matrix: ${{ fromJSON(needs.generate.outputs.matrix) }}
fail-fast: false

runs-on: ${{ matrix.runner }}
steps:
- if: ${{ matrix.asset != 'none' }}
uses: actions/cache@v3
with:
path: |
~/.stack
./.stack-work
key: ${{ runner.os }}-stack-${{ matrix.ghc }}
restore-keys: |
${{ runner.os }}-stack-

- if: ${{ matrix.asset != 'none' }}
run: |
cat >stack.yaml <<'EOM'
resolver: ${{ matrix.resolver }}
packages: []
extra-deps: [${{ matrix.extra-deps }}]
EOM

stack install weeder-${{ matrix.version }} --local-bin-path .

${{ matrix.zip }} '${{ matrix.asset }}' ./weeder
gh --repo '${{ github.repository }}' release upload '${{ matrix.release }}' '${{ matrix.asset }}'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8 changes: 3 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,19 @@ jobs:
steps:
- uses: actions/checkout@v2

- uses: freckle/stack-cache-action@main
- uses: freckle/stack-cache-action@v2
with:
working-directory: example

- uses: freckle/stack-action@main
- uses: freckle/stack-action@v3
with:
working-directory: example
hlint: false
weeder: false

- id: weeder
uses: ./
with:
ghc-version: 9.2.5
working-directory: example
weeder-version: 2.2.0
fail: false

- run: |
Expand Down
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ See the [Weeder README][weeder] for project requirements.
You will need to run this step in the same Job as you compile your project, or
make the `.hie` files available some other way.

This Action only supports [Stack]-based projects at this time: it uses
`stack install` to install `weeder` and `stack exec` to run it. PRs are very
welcome to support alternatives such as Cabal or Nix.

[stack]: https://docs.haskellstack.org/en/stable/README/

## Usage

```yaml
Expand All @@ -32,7 +26,30 @@ steps:

## Inputs

See [`action.yml`](./action.yml) for a complete and up to date list.
- **ghc-version**: The version of `weeder` to install and run

You must specify the `ghc-version` your project is compiled with (to ensure
`.hie` compatibility).

This Action maintains and installs pre-compiled `weeder` binaries for Mac and
Linux across all GHC versions that `weeder` compiles on (8.8.1 to 9.2.5 at
time of this writing). Please file an Issue if you're using a GHC that's not
supported, but for which a released version of `weeder` does exist.

- **weeder-arguments**: Arguments to pass when invoking `weeder`

Default is `--require-hs-files`, which ensures that cached builds that have
since removed files (but still have their `.hie` files present) don't generate
false positives.

- **working-directory**: Change to this directory before running.

This can be necessary if in a mono-repository.

- **fail**: Fail if we find unused functions?

Default is true. This is useful if you want to not fail the step, but do
something else with the weeder output yourself.

## Outputs

Expand Down
36 changes: 12 additions & 24 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
name: Weeder
description: Annotate unused functions in a Haskell project
inputs:
working-directory:
description: Change to this directory before operating
required: true
default: .
stack-yaml:
description: Path to stack.yaml, relative to working-directory
ghc-version:
description: Full version of GHC your project uses (required)
required: true
default: stack.yaml
weeder-version:
description: Version of weeder to install (default latest)
required: true
default: ""
weeder-arguments:
description: |
Arguments to pass when invoking weeder (default --require-hs-files)
required: true
default: --require-hs-files
working-directory:
description: Change to this directory before operating
required: true
default: .
fail:
description: Fail the build if unused functions found? (default true)
required: true
Expand All @@ -30,17 +25,11 @@ runs:
using: composite
steps:
- name: Install weeder
shell: bash
run: |
if [[ -n "${{ inputs.weeder-version }}" ]]; then
package=weeder-${{ inputs.weeder-version }}
else
package=weeder
fi

cd '${{ inputs.working-directory }}'
stack --stack-yaml '${{ inputs.stack-yaml }}' install \
--copy-compiler-tool "$package"
uses: pbrisbin/[email protected]
with:
name: weeder
version: ${{ inputs.ghc-version }}
url: "https://github.com/freckle/weeder-action/releases/download/Binaries/{name}-{version}-{os}-{arch}.{ext}"

- id: weeder
name: Run weeder
Expand All @@ -54,8 +43,7 @@ runs:

cd '${{ inputs.working-directory }}'
prefix=$(echo '${{ inputs.working-directory }}' | sed 's|/$||')/
stack --stack-yaml '${{ inputs.stack-yaml }}' exec -- \
weeder ${{ inputs.weeder-arguments }} |
weeder ${{ inputs.weeder-arguments }} |
sed "s|^|$prefix|; "'s/$/ is not used by any defined root/' |
tee "$tmp" || true

Expand Down
6 changes: 1 addition & 5 deletions example/stack.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
resolver: lts-18.16
extra-deps:
- dhall-1.40.1@sha256:ecc984210717ae2785a02c31c8b10c23a854761dba60c09adf533459bf5fe9b6,35396
- generic-lens-2.2.0.0@sha256:4008a39f464e377130346e46062e2ac1211f9d2e256bbb1857216e889c7196be,3867
- generic-lens-core-2.2.0.0@sha256:b6b69e992f15fa80001de737f41f2123059011a1163d6c8941ce2e3ab44f8c03,2913
resolver: lts-20.3
ghc-options:
"$locals": -fwrite-ide-info
8 changes: 4 additions & 4 deletions example/stack.yaml.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
packages: []
snapshots:
- completed:
size: 586286
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/16.yaml
sha256: cdead65fca0323144b346c94286186f4969bf85594d649c49c7557295675d8a5
original: lts-18.16
sha256: 03cec7d96ed78877b03b5c2bc5e31015b47f69af2fe6a62d994a42b7a43c5805
size: 648659
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/3.yaml
original: lts-20.3