diff --git a/.github/workflows/ipfs-deploy.yml b/.github/workflows/ipfs-deploy.yml index b937e40e..ff9419b9 100644 --- a/.github/workflows/ipfs-deploy.yml +++ b/.github/workflows/ipfs-deploy.yml @@ -29,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 @@ -57,3 +57,11 @@ 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 diff --git a/Dockerfile b/Dockerfile index 40a66c4d..76e421a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,7 @@ +# --------------------------------------------- +# App Setup: Install dependencies and build app +# --------------------------------------------- + FROM node:20-alpine3.19@sha256:e96618520c7db4c3e082648678ab72a49b73367b9a1e7884cf75ac30a198e454 as builder # Install app dependencies @@ -19,28 +23,98 @@ COPY ./app/img/ /source/app/img/ COPY ./app/ts/ /source/app/ts/ RUN npm 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/app /export RUN ipfs init +RUN ipfs add --cid-version 1 --quieter --only-hash -r /export > ipfs_hash.txt -# Copy lunaria build output -COPY --from=builder /source/app /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/lunaria: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") + + 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 + ;; -# 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 + *) + echo "Invalid option: $1" + echo "Example usage: docker run --rm ghcr.io/darkflorist/lunaria:latest [docker-host|nft.storage]" + exit 1 + ;; +esac +EOF -# print the hash for good measure in case someone is looking at the build logs -RUN cat ipfs_hash.txt +RUN chmod u+x /entrypoint.sh -# 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 +ENTRYPOINT [ "/entrypoint.sh" ] -ENTRYPOINT [ "./entrypoint.sh" ]