Skip to content

Commit

Permalink
Merge pull request #2 from amp-buildpacks/feat/issue-1
Browse files Browse the repository at this point in the history
issue(#1): Create buildpack for Aptos
  • Loading branch information
wangeguo authored Jan 27, 2024
2 parents fc958ff + 690d2f0 commit 35c7dbf
Show file tree
Hide file tree
Showing 12 changed files with 672 additions and 1 deletion.
13 changes: 13 additions & 0 deletions .github/pipeline-descriptor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
github:
username: ${{ github.actor }}
token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }}

package:
repositories: ["ghcr.io/amp-buildpacks/aptos"]
register: false
registry_token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }}

docker_credentials:
- registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }}
87 changes: 87 additions & 0 deletions .github/workflows/pb-update-pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Update Pipeline
"on":
push:
branches:
- main
paths:
- .github/pipeline-descriptor.yml
schedule:
- cron: 0 5 * * 1-5
workflow_dispatch: {}
jobs:
update:
name: Update Pipeline
runs-on:
- ubuntu-latest
steps:
- uses: actions/setup-go@v4
with:
go-version: "1.20"
- name: Install octo
run: |
#!/usr/bin/env bash
set -euo pipefail
go install -ldflags="-s -w" github.com/paketo-buildpacks/pipeline-builder/cmd/octo@latest
- uses: actions/checkout@v3
- name: Update Pipeline
id: pipeline
run: |
#!/usr/bin/env bash
set -euo pipefail
if [[ -f .github/pipeline-version ]]; then
OLD_VERSION=$(cat .github/pipeline-version)
else
OLD_VERSION="0.0.0"
fi
rm .github/workflows/pb-*.yml || true
octo --descriptor "${DESCRIPTOR}"
PAYLOAD=$(gh api /repos/paketo-buildpacks/pipeline-builder/releases/latest)
NEW_VERSION=$(jq -n -r --argjson PAYLOAD "${PAYLOAD}" '$PAYLOAD.name')
echo "${NEW_VERSION}" > .github/pipeline-version
RELEASE_NOTES=$(
gh api \
-F text="$(jq -n -r --argjson PAYLOAD "${PAYLOAD}" '$PAYLOAD.body')" \
-F mode="gfm" \
-F context="paketo-buildpacks/pipeline-builder" \
-X POST /markdown
)
git add .github/
git checkout -- .
echo "old-version=${OLD_VERSION}" >> "$GITHUB_OUTPUT"
echo "new-version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
DELIMITER=$(openssl rand -hex 16) # roughly the same entropy as uuid v4 used in https://github.com/actions/toolkit/blob/b36e70495fbee083eb20f600eafa9091d832577d/packages/core/src/file-command.ts#L28
printf "release-notes<<%s\n%s\n%s\n" "${DELIMITER}" "${RELEASE_NOTES}" "${DELIMITER}" >> "${GITHUB_OUTPUT}" # see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
env:
DESCRIPTOR: .github/pipeline-descriptor.yml
GITHUB_TOKEN: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }}
- uses: peter-evans/create-pull-request@v5
with:
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
body: |-
Bumps pipeline from `${{ steps.pipeline.outputs.old-version }}` to `${{ steps.pipeline.outputs.new-version }}`.
<details>
<summary>Release Notes</summary>
${{ steps.pipeline.outputs.release-notes }}
</details>
branch: update/pipeline
commit-message: |-
Bump pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }}
Bumps pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }}.
delete-branch: true
labels: semver:patch, type:task
signoff: true
title: Bump pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }}
token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }}
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) The Amphitheatre Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

bin/
dependencies/
package/
scratch/
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,70 @@
# aptos
# `ghcr.io/amp-buildpacks/aptos`

A Cloud Native Buildpack that provides the Aptos Tool Suite

## Configuration

| Environment Variable | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `$BP_APTOS_VERSION` | Configure the version of Aptos to install. It can be a specific version or a wildcard like `1.*`. It defaults to the latest `1.*` version. |


## Usage

### 1. To use this buildpack, simply run:

```shell
pack build <image-name> \
--path <aptos-samples-path> \
--buildpack ghcr.io/amp-buildpacks/aptos \
--builder paketobuildpacks/builder-jammy-base
```

For example:

```shell
pack build aptos-sample \
--path ./samples/aptos \
--buildpack ghcr.io/amp-buildpacks/aptos \
--builder paketobuildpacks/builder-jammy-base
```

### 2. To run the image, simply run:

```shell
docker run -u <uid>:<gid> -it <image-name>
```

For example:

```shell
docker run -u 1001:cnb -it aptos-sample
```

## Contributing

If anything feels off, or if you feel that some functionality is missing, please
check out the [contributing
page](https://docs.amphitheatre.app/contributing/). There you will find
instructions for sharing your feedback, building the tool locally, and
submitting pull requests to the project.

## License

Copyright (c) The Amphitheatre Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

## Credits

Heavily inspired by https://buildpacks.io/docs/buildpack-author-guide/create-buildpack/
131 changes: 131 additions & 0 deletions aptos/aptos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (c) The Amphitheatre Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package aptos

import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/buildpacks/libcnb"
"github.com/paketo-buildpacks/libpak"
"github.com/paketo-buildpacks/libpak/bard"
"github.com/paketo-buildpacks/libpak/crush"
"github.com/paketo-buildpacks/libpak/effect"
"github.com/paketo-buildpacks/libpak/sherpa"
)

type Aptos struct {
LayerContributor libpak.DependencyLayerContributor
Logger bard.Logger
Executor effect.Executor
}

func NewAptos(dependency libpak.BuildpackDependency, cache libpak.DependencyCache) Aptos {
contributor := libpak.NewDependencyLayerContributor(dependency, cache, libcnb.LayerTypes{
Build: true,
Cache: true,
Launch: true,
})
return Aptos{
LayerContributor: contributor,
Executor: effect.NewExecutor(),
}
}

func (r Aptos) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
r.LayerContributor.Logger = r.Logger
return r.LayerContributor.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
bin := filepath.Join(layer.Path, "bin")

r.Logger.Bodyf("Expanding %s to %s", artifact.Name(), bin)
if err := crush.Extract(artifact, bin, 0); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to expand %s\n%w", artifact.Name(), err)
}

// Must be set to executable
file := filepath.Join(bin, PlanEntryAptos)
r.Logger.Bodyf("Setting %s as executable", file)
if err := os.Chmod(file, 0755); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to chmod %s\n%w", file, err)
}

// Must be set to PATH
r.Logger.Bodyf("Setting %s in PATH", bin)
if err := os.Setenv("PATH", sherpa.AppendToEnvVar("PATH", ":", bin)); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to set $PATH\n%w", err)
}

// get version
buf, err := r.Execute(PlanEntryAptos, []string{"--version"})
if err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to get %s version\n%w", PlanEntryAptos, err)
}
version := strings.Split(strings.TrimSpace(buf.String()), " ")[1]
r.Logger.Bodyf("Checking %s version: %s", PlanEntryAptos, version)

// set MOVE_HOME
moveHome := "/workspace"
r.Logger.Bodyf("Setting MOVE_HOME = %s", moveHome)
if err := os.Setenv("MOVE_HOME", moveHome); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to set MOVE_HOME\n%w", err)
}

// compile contract
args := []string{"move", "compile"}
r.Logger.Bodyf("Compiling contracts by '%s %s'", PlanEntryAptos, args)
if _, err := r.Execute(PlanEntryAptos, args); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to compile contract\n%w", err)
}

layer.LaunchEnvironment.Append("PATH", ":", bin)
layer.LaunchEnvironment.Default("MOVE_HOME", moveHome)
return layer, nil
})
}

func (r Aptos) Execute(command string, args []string) (*bytes.Buffer, error) {
buf := &bytes.Buffer{}
if err := r.Executor.Execute(effect.Execution{
Command: command,
Args: args,
Stdout: buf,
Stderr: buf,
}); err != nil {
return buf, fmt.Errorf("%s: %w", buf.String(), err)
}
return buf, nil
}

func (r Aptos) BuildProcessTypes(cr libpak.ConfigurationResolver, app libcnb.Application) ([]libcnb.Process, error) {
processes := []libcnb.Process{}

enableDeploy := cr.ResolveBool("BP_ENABLE_APTOS_PROCESS")
if enableDeploy {
processes = append(processes, libcnb.Process{
Type: PlanEntryAptos,
Command: PlanEntryAptos,
Arguments: []string{"move", "publish", "--skip-fetch-latest-git-deps", "--assume-yes"},
Default: true,
})
}
return processes, nil
}

func (r Aptos) Name() string {
return r.LayerContributor.LayerName()
}
73 changes: 73 additions & 0 deletions aptos/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) The Amphitheatre Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package aptos

import (
"fmt"

"github.com/buildpacks/libcnb"
"github.com/paketo-buildpacks/libpak"
"github.com/paketo-buildpacks/libpak/bard"
)

type Build struct {
Logger bard.Logger
}

func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
b.Logger.Title(context.Buildpack)
result := libcnb.NewBuildResult()

pr := libpak.PlanEntryResolver{Plan: context.Plan}

if _, ok, err := pr.Resolve(PlanEntryAptos); err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to resolve Aptos plan entry\n%w", err)
} else if ok {
cr, err := libpak.NewConfigurationResolver(context.Buildpack, &b.Logger)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to create configuration resolver\n%w", err)
}

dc, err := libpak.NewDependencyCache(context)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to create dependency cache\n%w", err)
}
dc.Logger = b.Logger

dr, err := libpak.NewDependencyResolver(context)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to create dependency resolver\n%w", err)
}

// install aptos
// update dependency.id from metadata.dependencies for buildpack.toml
v, _ := cr.Resolve("BP_APTOS_VERSION")
dependency, err := dr.Resolve(PlanEntryAptos, v)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err)
}

aptosLayer := NewAptos(dependency, dc)
aptosLayer.Logger = b.Logger

result.Processes, err = aptosLayer.BuildProcessTypes(cr, context.Application)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to build list of process types\n%w", err)
}
result.Layers = append(result.Layers, aptosLayer)
}

return result, nil
}
Loading

0 comments on commit 35c7dbf

Please sign in to comment.