diff --git a/.env b/.env new file mode 100644 index 0000000..4bd5d72 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +EARTHLY_INSTALLATION_NAME=earthbuild-tap \ No newline at end of file diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 1003708..fe3b20b 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -7,4 +7,22 @@ ":semanticCommits", ], labels: ["renovate"], + customManagers: [ + { + customType: "regex", + fileMatch: ["^Formula/earth\\.rb$"], + matchStrings: [ + "version\\s+\"(?.*?)\"" + ], + datasourceTemplate: "github-tags", + depNameTemplate: "EarthBuild/earthbuild" + } + ], + packageRules: [ + { + matchPackageNames: ["EarthBuild/earthbuild"], + branchName: "release-v{{{newVersion}}}", + automerge: true + } + ], } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..2d59de3 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,28 @@ +name: CI + +on: + pull_request: + +permissions: {} + +jobs: + check: + runs-on: ubuntu-24.04 + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + token: ${{ secrets.GITHUB_TOKEN }} + - uses: earthbuild/actions-setup@5d323543fa1d7b963384b46b2cbaef0bf6d88216 # v2.1.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Bootstrap buildkitd + run: earth bootstrap + + - name: Lint + run: earth --ci +lint + + - name: Test + run: earth --ci +test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..4d549d9 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,36 @@ +name: Release + +on: + pull_request: + branches: + - main + +permissions: {} + +jobs: + update-sha: + permissions: + contents: write + runs-on: ubuntu-24.04-arm + if: github.actor == 'renovate[bot]' && startsWith(github.head_ref, 'release-v') + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ github.event.pull_request.head.ref }} + + - name: Update checksums + run: python3 scripts/update-checksums.py + + - name: Commit and push changes + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + if ! git diff --exit-code Formula/earth.rb; then + git add Formula/earth.rb + git commit -m "chore: update sha256 checksums" + git push + else + echo "No checksum changes detected." + fi diff --git a/.github/workflows/test-and-publish.yml b/.github/workflows/test-and-publish.yml deleted file mode 100644 index 7a01501..0000000 --- a/.github/workflows/test-and-publish.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: brew test and publish bot -on: - push: - branches: - - release-* -jobs: - release: - runs-on: macos-latest - steps: - - name: Set up Homebrew - id: set-up-homebrew - uses: Homebrew/actions/setup-homebrew@master - - - name: Set up git - uses: Homebrew/actions/git-user-config@master - - - name: Cache Homebrew Bundler RubyGems - id: cache - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ steps.set-up-homebrew.outputs.gems-path }} - key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} - restore-keys: ${{ runner.os }}-rubygems- - - - name: Install Homebrew Bundler RubyGems - if: steps.cache.outputs.cache-hit != 'true' - run: brew install-bundler-gems - - - name: cleanup - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} - run: brew test-bot --only-cleanup-before - - - name: setup - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} - run: brew test-bot --only-setup - - - name: syntax check - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} - run: brew test-bot --only-tap-syntax - - - name: brew update - env: - HOMEBREW_NO_INSTALL_FROM_API: 1 - run: brew update - - - name: build earthly bottles - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} - run: brew test-bot --only-formulae earthly - - # homebrew intentially adds in two hyphens under - # https://github.com/Homebrew/brew/blob/b55498269f1fb0380cfd7122f6bbc0fc0125c35f/Library/Homebrew/software_spec.rb#L279 - - name: remove double hyphens which are produced by test-bot - run: find earthly--*.bottle.* | awk -F "--" '{print "mv " $0 " " $1"-"$2}' | sh - - - name: move bottles into bottles/ dir - run: mkdir bottles/ && mv ./*.bottle.* bottles/ - - - name: merge bottles - env: - HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} - run: brew bottle --merge --root-url "https://github.com/$GITHUB_REPOSITORY/releases/download/" --write bottles/*.json - - # "brew test-bot" removes dependencies; we must re-install them here - - name: (re)install dependencies - run: brew install jq npm - - - name: setup github-release - run: npm install -g github-release-cli@v1.3.1 - - - name: release bottles - env: - GITHUB_TOKEN: ${{ github.token }} - run: |- - set -e - # shellcheck disable=SC2153 - VERSION="${GITHUB_REF#refs/heads/release-v}" - if ! echo "$VERSION" | grep '^[0-9]\+\.[0-9]\+\.[0-9]\+$' >/dev/null; then - echo "ERROR: failed to detect semantic version; got $VERSION" - exit 1 - fi - RELEASE_TAG="earthly-$VERSION" - # first delete any previously released files (needed in case the previous upload attempt failed) - PREV_RELEASE_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG" | jq .id) - if [ -n "$PREV_RELEASE_ID" ] && [ "$PREV_RELEASE_ID" != "null" ]; then - echo "deleting previous release ID $PREV_RELEASE_ID" - curl -s -H "Authorization: token $GITHUB_TOKEN" --request DELETE "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/$PREV_RELEASE_ID" - fi - # next make sure any previous tag is deleted (otherwise github will create an untagged release name vX.Y.Z) - echo "deleting tag $RELEASE_TAG (in case it already exists)" - curl -s -H "Authorization: token $GITHUB_TOKEN" --request DELETE "https://api.github.com/repos/$GITHUB_REPOSITORY/git/refs/tags/$RELEASE_TAG" - GITHUB_OWNER=$(dirname "$GITHUB_REPOSITORY") - GITHUB_REPO=$(basename "$GITHUB_REPOSITORY") - github-release upload \ - --owner "$GITHUB_OWNER" \ - --repo "$GITHUB_REPO" \ - --prerelease false \ - --commitish "$GITHUB_SHA" \ - --tag "$RELEASE_TAG" \ - --name "$RELEASE_TAG" \ - --body "earthly: update $VERSION bottle." \ - ./bottles/*.tar.gz 2>&1 | tee /tmp/release.log - if grep -i error /tmp/release.log > /dev/null; then - echo "ERROR: github-release upload failed: check the above release.log output" && exit 1 - fi - - - name: merge into main and delete release branch - env: - GITHUB_TOKEN: ${{ github.token }} - run: |- - # this should be different than GITHUB_SHA, due to brew bottle comitting a change - SHA=$(git rev-parse HEAD) - git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/"$GITHUB_REPOSITORY" - git fetch -a - git checkout main - git reset --hard origin/main - git merge "$SHA" - git push origin main - git push origin --delete "$GITHUB_REF" - curl -s -X POST -H 'Content-type: application/json' --data '{"text":"homebrew-earthly: Successfully merged release branch into main"}' "${{ secrets.SLACK_RELEASE_WEBHOOK_URL }}" - - - name: post to slack on failure - run: |- - curl -s -X POST -H 'Content-type: application/json' --data '{ "attachments": [ { "fallback": "Failed to build release", "title": "earthly/homebrew-earthly tap", "title_link": "'"$GITHUB_SERVER_URL"'/'"$GITHUB_REPOSITORY"'/actions/runs/'"$GITHUB_RUN_ID"', "text": "Failed to build release!", "color": "#CC0000" } ] }' "${{ secrets.SLACK_RELEASE_WEBHOOK_URL }}" - if: ${{ failure() }} diff --git a/.gitignore b/.gitignore index f410c0c..2211df6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ *.txt -earthbuild*.json -earthbuild*.tar.gz \ No newline at end of file diff --git a/Earthfile b/Earthfile new file mode 100644 index 0000000..02970ee --- /dev/null +++ b/Earthfile @@ -0,0 +1,81 @@ +VERSION 0.8 +FROM debian +ENV NONINTERACTIVE=1 +ENV HOMEBREW_NO_AUTO_UPDATE=1 +ENV PATH="/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:${PATH}" +WORKDIR /home/linuxbrew/earthbuild-tap +RUN apt-get update && apt-get install -y curl git ca-certificates procps sudo build-essential +RUN useradd -m -s /bin/bash linuxbrew && \ + echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ + chown -R linuxbrew:linuxbrew /home/linuxbrew +USER linuxbrew +RUN git config --global --add safe.directory /home/linuxbrew/earthbuild-tap && \ + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && \ + /home/linuxbrew/.linuxbrew/bin/brew developer on + +src: + COPY --dir .git Formula . + RUN brew tap EarthBuild/tap . && brew trust EarthBuild/tap + SAVE ARTIFACT Formula + SAVE ARTIFACT .git + +# check verifies the quality of the formula +check: + BUILD +lint + BUILD +test + +# lint checks for Homebrew code quality +lint: + BUILD +info + BUILD +readall + BUILD +audit + BUILD +style + BUILD +fetch + BUILD +livecheck + +# audit checks for Homebrew coding style violations +audit: + FROM +src + RUN brew audit --strict --online --except=specs --signing --debug --audit-debug EarthBuild/tap/earth + +# style checks for conformance to Homebrew style guidelines +style: + FROM +src + RUN brew style --verbose --debug EarthBuild/tap/earth + +# info checks that the formula parses correctly +info: + FROM +src + RUN brew info EarthBuild/tap/earth + +# readall checks that all formulae in the tap can be successfully parsed +readall: + FROM +src + RUN brew readall EarthBuild/tap + +# fetch verifies source URLs and sha256 checksums +fetch: + FROM +src + RUN brew fetch EarthBuild/tap/earth + +# livecheck checks if there is a newer version available upstream +livecheck: + FROM +src + RUN brew livecheck EarthBuild/tap/earth + +# test runs all tests +test: + BUILD +test-install + BUILD +test-formula + +# test-install installs the pre-compiled binary +test-install: + FROM +src + RUN brew install EarthBuild/tap/earth + RUN earth --version + +# test-formula runs the built-in 'test do' block defined in the formula +test-formula: + FROM +src + RUN brew install EarthBuild/tap/earth + RUN brew test --verbose --debug EarthBuild/tap/earth diff --git a/Formula/earth.rb b/Formula/earth.rb index df23059..bf634c0 100644 --- a/Formula/earth.rb +++ b/Formula/earth.rb @@ -1,44 +1,62 @@ class Earth < Formula desc "Build automation tool for the container era" - homepage "https://github.com/earthbuild" - url "https://github.com/EarthBuild/earthbuild.git", - tag: "v0.8.17", - revision: "52f2da6dd7f3de24a60a76e00044ec560b0ea407" + homepage "https://github.com/EarthBuild/earthbuild" + version "0.8.17" license "MPL-2.0" - head "https://github.com/EarthBuild/earthbuild.git", branch: "main" - bottle do - sha256 cellar: :any_skip_relocation, arm64_tahoe: "194e4b767c3d1a551453ceb3739345c84de89533768b352e3b339d116497a238" + on_macos do + on_arm do + url "https://github.com/EarthBuild/earthbuild/releases/download/v#{version}/earth-darwin-arm64" + sha256 "2e0a5e7b5623e2bfdab3e0be6bbbcb772f1d2ad6562132fbc3c9ce5564a939c1" + end + on_intel do + url "https://github.com/EarthBuild/earthbuild/releases/download/v#{version}/earth-darwin-amd64" + sha256 "4ba8af21431b276edfacf8730e9372da1842ead0bc9bf0f6a014896afca97c96" + end end - depends_on "go" => :build + on_linux do + on_arm do + url "https://github.com/EarthBuild/earthbuild/releases/download/v#{version}/earth-linux-arm64" + sha256 "bdc776167083e1bc4ec01379e88c6ae6372f52e4ea034e931865ff4ba030df63" + end + on_intel do + url "https://github.com/EarthBuild/earthbuild/releases/download/v#{version}/earth-linux-amd64" + sha256 "85b7f31020be220493c1ef89fe4e976985a72e54dd12b7dfcf17544c8d4fd880" + end + end def install - ENV["CGO_ENABLED"] = "0" - ldflags = %W[ - -s -w - -X main.DefaultBuildkitdImage=docker.io/earthly/buildkitd:v0.8.16 - -X main.Version=v#{version} - -X main.GitSha=#{Utils.git_head} - -X main.BuiltBy=homebrew-earthbuild - ] - tags = "dfrunmount dfrunsecurity dfsecrets dfssh dfrunnetwork dfheredoc forceposix" - system "go", "build", "-tags", tags, *std_go_args(ldflags: ldflags, output: bin/"earthly"), "./cmd/earthly" + binary_name = if OS.mac? + Hardware::CPU.arm? ? "earth-darwin-arm64" : "earth-darwin-amd64" + else + Hardware::CPU.arm? ? "earth-linux-arm64" : "earth-linux-amd64" + end - bin.install_symlink "earthly" => "earth" + chmod 0755, binary_name + bin.install binary_name => "earth" + bin.install_symlink "earth" => "earthly" generate_completions_from_executable(bin/"earth", "bootstrap", "--source", shells: [:bash, :zsh]) end + def caveats + <<~EOS + EarthBuild requires a container runtime to function. + If you don't have one, you can install Docker or Podman: + brew install --cask docker + OR + brew install podman + EOS + end + test do - # earthbuild requires docker to run; therefore doing a complete end-to-end test here is not - # possible; however the "earthbuild ls" command is able to run without docker. - (testpath/"Earthfile").write <<~EOS + (testpath / "Earthfile").write <<~EOS VERSION 0.8 mytesttarget: \tRUN echo Homebrew EOS - output = shell_output("#{bin}/earthly ls") + output = shell_output("#{bin}/earth ls") assert_match "+mytesttarget", output end end diff --git a/README.md b/README.md index df59643..e3d7871 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,22 @@ -# homebrew-earthbuild +# homebrew-tap -Before you begin, ensure you have Homebrew installed on your macOS system. If you don't, you can install it by following the instructions on the [official Homebrew website](https://brew.sh/). +This repository contains the homebrew formula required to install `earth` on MacOS and Linux via `brew`. -This repository contains the homebrew formula required to install `EarthBuild` on MacOS via `brew`. +Before you begin, ensure you have Homebrew installed on your macOS or Linux system. If you don't, you can install it by following the instructions on the [official Homebrew website](https://brew.sh/). -## Installation - -**Only alpha version is available at the moment. Stable version coming soon.** -First, add this tap to your local Homebrew setup. This makes the formulas within it available for installation. -```shell -brew tap earthbuild/earthbuild -``` +## Installation -For the latest stable version, run: +You can install `earth` directly from this tap using: ```shell -brew install earth +brew install earthbuild/tap/earth ``` -To install the alpha version directly from the main branch (which may be unstable), run: +Or you can tap the repository first and then install: ```shell -brew install --HEAD earth +brew tap earthbuild/tap +brew install earth ``` diff --git a/scripts/update-checksums.py b/scripts/update-checksums.py new file mode 100644 index 0000000..c15c1e0 --- /dev/null +++ b/scripts/update-checksums.py @@ -0,0 +1,62 @@ +import urllib.request +import re +import sys + +def main(): + # 1. Parse version from Formula/earth.rb + with open("Formula/earth.rb", "r") as f: + content = f.read() + + m = re.search(r'version "([0-9.]+)"', content) + if not m: + print("Error: version not found in Formula/earth.rb") + sys.exit(1) + version = m.group(1) + + print(f"Detected version: {version}") + + # 2. Fetch checksum.asc + url = f"https://github.com/EarthBuild/earthbuild/releases/download/v{version}/checksum.asc" + print(f"Fetching checksums from: {url}") + try: + with urllib.request.urlopen(url, timeout=60) as response: + checksums_text = response.read().decode('utf-8') + except Exception as e: + print(f"Error fetching checksums: {e}") + sys.exit(1) + + # 3. Parse hashes + hashes = {} + for line in checksums_text.splitlines(): + parts = line.split() + if len(parts) == 2: + filename = parts[1].lstrip('*') + hashes[filename] = parts[0] + + required_binaries = [ + "earth-darwin-arm64", + "earth-darwin-amd64", + "earth-linux-arm64", + "earth-linux-amd64" + ] + for b in required_binaries: + if b not in hashes: + print(f"Error: checksum for {b} not found in checksum.asc") + sys.exit(1) + + # 4. Update sha256 hashes in earth.rb + for b in required_binaries: + pattern = r'(url\s+"https://github\.com/EarthBuild/earthbuild/releases/download/v#\{version\}/%s"\s+sha256\s+")[a-f0-9]+(")' % b + content, count = re.subn(pattern, rf'\g<1>{hashes[b]}\g<2>', content) + if count == 0: + print(f"Error: failed to replace sha256 for {b} in Formula/earth.rb") + sys.exit(1) + print(f"Updated {b} sha256 to {hashes[b]}") + + with open("Formula/earth.rb", "w") as f: + f.write(content) + + print("Formula/earth.rb updated successfully!") + +if __name__ == "__main__": + main()