Skip to content
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

Update ipfs deploy workflow #102

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
97 changes: 91 additions & 6 deletions .github/workflows/ipfs-deploy.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
name: IPFS deploy
name: Build and Push to IPFS

on:
workflow_dispatch:
push:
# Publish `master` as Docker `latest` image.
branches:
- master

# Publish `v1` tags as releases.
tags:
- 'v\d+'

Expand All @@ -10,10 +15,12 @@ env:
REGISTRY: ghcr.io

jobs:
deploy-to-prod:
# Push image to GitHub Packages.
# See also https://docs.docker.com/docker-hub/builds/
push:
runs-on: ubuntu-latest
environment:
name: deploy/prod
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v2

Expand All @@ -22,7 +29,7 @@ jobs:

- name: Build image
run: |
docker build . --file Dockerfile --tag $IMAGE_TAG
docker build --file Dockerfile --tag $IMAGE_TAG .

# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
Expand Down Expand Up @@ -50,3 +57,81 @@ jobs:

docker tag $IMAGE_TAG $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION

# Make image reference available to subsequent steps
echo "IMAGE_RELEASE_ID=$(echo $IMAGE_ID:$VERSION)" >> $GITHUB_ENV

# Run docker image script to publish app to nft.storage
- name: Publish to nft.storage
run: |
docker run -e NFTSTORAGE_API_KEY=${{ secrets.NFTSTORAGE_API_KEY }} $IMAGE_RELEASE_ID nft.storage

- name: Create a reference for IPFS hash
if: github.ref_type == 'tag'
run: |
echo "IPFS_HASH=$(docker run --entrypoint /bin/sh $IMAGE_RELEASE_ID -c 'cat /ipfs_hash.txt')" >> $GITHUB_ENV

- name: Create a release
if: github.ref_type == 'tag'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Markdown template for the release notes
RELEASE_NOTE_TEMPLATE=$(cat << EOF
#### IPFS Hash

\`\`\`
$IPFS_HASH
\`\`\`

You can view published versions of Horswap through any IPFS Gateway

[ipfs://$IPFS_HASH](ipfs://$IPFS_HASH) __(Recommended)__
_requires Brave Browser or IPFS Desktop_
[https://$IPFS_HASH.ipfs.nftstorage.link](https://$IPFS_HASH.ipfs.nftstorage.link)
[https://$IPFS_HASH.ipfs.zoltu.io](https://$IPFS_HASH.ipfs.zoltu.io)
[https://$IPFS_HASH.ipfs.keydonix.com](https://$IPFS_HASH.ipfs.keydonix.com)
[https://$IPFS_HASH.ipfs.cf-ipfs.com](https://$IPFS_HASH.ipfs.cf-ipfs.com)
[https://$IPFS_HASH.ipfs.w3s.link](https://$IPFS_HASH.ipfs.w3s.link)
EOF
)

# Generate payload for creating a new release
PAYLOAD_TEMPLATE=$(cat <<EOF
{
"name": "$GITHUB_REF_NAME",
"tag_name": "$GITHUB_REF_NAME",
"body": $(echo "$RELEASE_NOTE_TEMPLATE" | jq -cRs '@json|fromjson'),
"draft": false,
"generate_release_notes": true
}
EOF
)

# Create a github release
# https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release
REQUEST_DATA=$(echo "$PAYLOAD_TEMPLATE" | jq -c)
RESPONSE=$(curl \
--silent \
--location \
--request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer $GITHUB_TOKEN" \
--header "X-GitHub-Api-Version: 2022-11-28" \
--data "$REQUEST_DATA" \
--write-out "%{http_code}" \
"https://api.github.com/repos/$GITHUB_REPOSITORY/releases"
)

# Extract the response body and the appended http code
RESPONSE_CODE=${RESPONSE: -3}
RESPONSE_BODY=${RESPONSE//$RESPONSE_CODE/}

# Successful creation will return a status 201 (Created), otherwise show the error
if [ "$RESPONSE_CODE" -ne 201 ]; then
ERROR_MESSAGE=$(echo "$RESPONSE_BODY" | jq '.message')
echo "HTTP $RESPONSE_CODE - $ERROR_MESSAGE"
exit 1
fi

echo "Release ($GITHUB_REF_NAME) successfully created"
93 changes: 83 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# ---------------------------------------------
# App Setup: Install dependencies and build app
# ---------------------------------------------

FROM node:18.19.0-alpine3.18@sha256:c0a5f02df6e631b75ee3037bd4389ac1f91e591c5c1e30a0007a7d0babcd4cd3 as builder

# Get git
Expand All @@ -21,28 +25,97 @@ COPY ./.eslintrc.js /source/.eslintrc.js
COPY ./.swcrc /source/.swcrc
RUN yarn run build

# --------------------------------------------------------
# Base Image: Create the base image that will host the app
# --------------------------------------------------------

# Cache the kubo image
FROM ipfs/kubo:v0.25.0@sha256:0c17b91cab8ada485f253e204236b712d0965f3d463cb5b60639ddd2291e7c52 as ipfs-kubo

# Create the base image
FROM debian:12.2-slim@sha256:93ff361288a7c365614a5791efa3633ce4224542afb6b53a1790330a8e52fc7d

# Add curl to the base image (7.88.1-10+deb12u5)
# Add jq to the base image (1.6-2.1)
RUN apt-get update && apt-get install -y curl=7.88.1-10+deb12u5 jq=1.6-2.1

# Install kubo and initialize ipfs
COPY --from=ipfs-kubo /usr/local/bin/ipfs /usr/local/bin/ipfs

# Copy app's build output and initialize IPFS api
COPY --from=builder /source/build /export
RUN ipfs init
RUN ipfs add --cid-version 1 --quieter --only-hash -r /export > ipfs_hash.txt

# Copy build output
COPY --from=builder /source/build /export
# --------------------------------------------------------
# Publish Script: Option to host app locally or on nft.storage
# --------------------------------------------------------

WORKDIR ~
COPY <<'EOF' /entrypoint.sh
#!/bin/sh
set -e

if [ $# -ne 1 ]; then
echo "Example usage: docker run --rm ghcr.io/darkflorist/horswap:latest [docker-host|nft.storage]"
exit 1
fi

case $1 in

docker-host)
# Show the IFPS build hash
echo "Build Hash: $(cat /ipfs_hash.txt)"

# Determine the IPV4 address of the docker-hosted IPFS instance
IPFS_IP4_ADDRESS=$(getent ahostsv4 host.docker.internal | grep STREAM | head -n 1 | cut -d ' ' -f 1)

echo "Adding files to docker running IPFS at $IPFS_IP4_ADDRESS"
IPFS_HASH=$(ipfs add --api /ip4/$IPFS_IP4_ADDRESS/tcp/5001 --cid-version 1 --quieter -r /export)
echo "Uploaded Hash: $IPFS_HASH"
;;

nft.storage)
if [ -z $NFTSTORAGE_API_KEY ] || [ $NFTSTORAGE_API_KEY = "" ]; then
echo "NFTSTORAGE_API_KEY environment variable is not set";
exit 1;
fi

# Show the IFPS build hash
echo "Build Hash: $(cat /ipfs_hash.txt)"

# Create a CAR archive from build hash
echo "Uploading files to nft.storage..."
IPFS_HASH=$(ipfs add --cid-version 1 --quieter -r /export)
ipfs dag export $IPFS_HASH > output.car

# Upload the entire directory to nft.storage
UPLOAD_RESPONSE=$(curl \
--request POST \
--header "Authorization: Bearer $NFTSTORAGE_API_KEY" \
--header "Content-Type: application/car" \
--data-binary @output.car \
--silent \
https://api.nft.storage/upload)

# Show link to nft.storage (https://xxx.ipfs.nftstorage.link)
UPLOAD_SUCCESS=$(echo "$UPLOAD_RESPONSE" | jq -r ".ok")

# add the build output to IPFS and write the hash to a file
RUN ipfs add --cid-version 1 --quieter --only-hash --recursive /export > ipfs_hash.txt
if [ "$UPLOAD_SUCCESS" = "true" ]; then
echo "Succesfully uploaded to https://"$(echo "$UPLOAD_RESPONSE" | jq -r ".value.cid")".ipfs.nftstorage.link"
else
echo "Upload Failed: " $(echo "$UPLOAD_RESPONSE" | jq -r ".error | @json")
fi
;;

# print the hash for good measure in case someone is looking at the build logs
RUN cat ipfs_hash.txt
*)
echo "Invalid option: $1"
echo "Example usage: docker run --rm ghcr.io/darkflorist/horswap:latest [docker-host|nft.storage]"
exit 1
;;
esac
EOF

# this entrypoint file will execute `ipfs add` of the build output to the docker host's IPFS API endpoint, so we can easily extract the IPFS build out of the docker image
RUN printf '#!/bin/sh\nipfs --api /ip4/`getent ahostsv4 host.docker.internal | grep STREAM | head -n 1 | cut -d \ -f 1`/tcp/5001 add --cid-version 1 -r /export' >> entrypoint.sh
RUN chmod u+x entrypoint.sh
RUN chmod u+x /entrypoint.sh

ENTRYPOINT [ "./entrypoint.sh" ]
ENTRYPOINT [ "/entrypoint.sh" ]
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ exports[`EmptyWalletContent.tsx matches base snapshot 1`] = `
/>
</svg>
<div
class="c1 c2 common__127l8hd0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
class="c1 c2 common__1cp2nzo0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
>
No NFTs yet
</div>
Expand Down Expand Up @@ -128,7 +128,7 @@ exports[`EmptyWalletContent.tsx matches base snapshot 1`] = `
/>
</svg>
<div
class="c1 c2 common__127l8hd0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
class="c1 c2 common__1cp2nzo0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
>
No tokens yet
</div>
Expand Down Expand Up @@ -174,7 +174,7 @@ exports[`EmptyWalletContent.tsx matches base snapshot 1`] = `
/>
</svg>
<div
class="c1 c2 common__127l8hd0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
class="c1 c2 common__1cp2nzo0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
>
No activity yet
</div>
Expand Down Expand Up @@ -209,7 +209,7 @@ exports[`EmptyWalletContent.tsx matches base snapshot 1`] = `
/>
</svg>
<div
class="c1 c2 common__127l8hd0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
class="c1 c2 common__1cp2nzo0 sprinkles_fontWeight_medium_sm__1jkzbi5d9 sprinkles_fontSize_28_sm__1jkzbi5bx sprinkles_lineHeight_36_sm__1jkzbi5el css-n8z49y"
>
No pools yet
</div>
Expand Down
Loading