|
| 1 | +name: Build and Release Contract |
| 2 | + |
| 3 | +on: |
| 4 | + workflow_call: |
| 5 | + inputs: |
| 6 | + relative_path: |
| 7 | + description: "Relative path to the working directory" |
| 8 | + type: string |
| 9 | + required: false |
| 10 | + make_target: |
| 11 | + description: "Make target for the contract" |
| 12 | + type: string |
| 13 | + required: false |
| 14 | + package: |
| 15 | + description: "Package to build" |
| 16 | + type: string |
| 17 | + required: false |
| 18 | + release_name: |
| 19 | + description: "Name for the release" |
| 20 | + required: true |
| 21 | + type: string |
| 22 | + release_description: |
| 23 | + description: "Description for the release" |
| 24 | + required: false |
| 25 | + type: string |
| 26 | + home_domain: |
| 27 | + description: "Home domain" |
| 28 | + required: false |
| 29 | + type: string |
| 30 | + secrets: |
| 31 | + release_token: |
| 32 | + description: "Github token" |
| 33 | + required: true |
| 34 | + |
| 35 | +permissions: |
| 36 | + id-token: write |
| 37 | + contents: write |
| 38 | + attestations: write |
| 39 | + |
| 40 | +jobs: |
| 41 | + build: |
| 42 | + runs-on: ubuntu-latest |
| 43 | + steps: |
| 44 | + - uses: cargo-bins/cargo-binstall@main |
| 45 | + - name: install scaffold-stellar |
| 46 | + run: cargo binstall -y stellar-scaffold-cli |
| 47 | + - name: Set working directory |
| 48 | + run: | |
| 49 | + RANDOM_DIR=$(openssl rand -hex 8) |
| 50 | + WORK_DIR="${{ github.workspace }}/$RANDOM_DIR" |
| 51 | + mkdir -p "$WORK_DIR" |
| 52 | + echo "WORK_DIR=$WORK_DIR" >> $GITHUB_ENV |
| 53 | + echo "Using working directory: $WORK_DIR" |
| 54 | +
|
| 55 | + - name: Checkout code |
| 56 | + uses: actions/checkout@v6 |
| 57 | + with: |
| 58 | + path: ${{ env.WORK_DIR }} |
| 59 | + |
| 60 | + - name: Set relative path |
| 61 | + run: | |
| 62 | + # Set relative path after checking out the code |
| 63 | + if [ "${{ inputs.relative_path }}" ]; then |
| 64 | + WORK_DIR="$WORK_DIR/${{ inputs.relative_path }}" |
| 65 | + echo "WORK_DIR=$WORK_DIR" >> $GITHUB_ENV |
| 66 | + echo "Using relative path: $WORK_DIR" |
| 67 | + fi |
| 68 | +
|
| 69 | + - name: Run Make (if applicable) |
| 70 | + if: inputs.make_target != '' |
| 71 | + working-directory: ${{ env.WORK_DIR }} |
| 72 | + run: | |
| 73 | + make ${{ inputs.make_target }} |
| 74 | +
|
| 75 | + - name: Update Rust and Add wasm32 Target |
| 76 | + working-directory: ${{ env.WORK_DIR }} |
| 77 | + run: | |
| 78 | + rustup update |
| 79 | + rustup target add wasm32v1-none |
| 80 | +
|
| 81 | + - name: Print versions |
| 82 | + run: | |
| 83 | + rustc --version |
| 84 | + cargo --version |
| 85 | +
|
| 86 | + - name: Install jq |
| 87 | + run: sudo apt-get update && sudo apt-get install -y jq |
| 88 | + |
| 89 | + - name: Get Cargo.toml metadata |
| 90 | + working-directory: ${{ env.WORK_DIR }} |
| 91 | + run: | |
| 92 | + if [ ! -f "Cargo.toml" ]; then |
| 93 | + echo "Cargo.toml does not exist" |
| 94 | + exit 1 |
| 95 | + fi |
| 96 | + CARGO_METADATA=$(cargo metadata --format-version=1 --no-deps) |
| 97 | + echo "CARGO_METADATA=$CARGO_METADATA" >> $GITHUB_ENV |
| 98 | +
|
| 99 | + - name: Set output directory path |
| 100 | + run: | |
| 101 | + RANDOM_DIR=$(openssl rand -hex 8) |
| 102 | + OUTPUT="$WORK_DIR/$RANDOM_DIR" |
| 103 | + echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV |
| 104 | +
|
| 105 | + - name: Build contract |
| 106 | + uses: stellar/stellar-cli@v25.1.0 |
| 107 | + with: |
| 108 | + version: "22.8.1" |
| 109 | + - run: | |
| 110 | + # Navigate to the working directory |
| 111 | + cd ${WORK_DIR} |
| 112 | +
|
| 113 | + # Build command arguments |
| 114 | + COMMAND_ARGS="--out-dir ${OUTPUT} --meta source_repo=github:${{ github.repository }}" |
| 115 | + if [ "${{ inputs.package }}" ]; then |
| 116 | + COMMAND_ARGS="--package ${{ inputs.package }} $COMMAND_ARGS" |
| 117 | + PACKAGE_NAME=${{ inputs.package }} |
| 118 | + else |
| 119 | + PACKAGE_NAME=$(grep -m1 '^name =' Cargo.toml | cut -d '"' -f2) |
| 120 | + fi |
| 121 | + if [ "${{ inputs.home_domain }}" ]; then |
| 122 | + COMMAND_ARGS="$COMMAND_ARGS --meta home_domain=${{ inputs.home_domain }}" |
| 123 | + fi |
| 124 | +
|
| 125 | + # Build the contract |
| 126 | + stellar scaffold build $COMMAND_ARGS |
| 127 | +
|
| 128 | + # Get the package version |
| 129 | + PACKAGE_VERSION=$(echo "$CARGO_METADATA" | jq '.packages[] | select(.name == "'"${PACKAGE_NAME}"'") | .version' | sed -e 's/"//g') |
| 130 | + if [ -z "$PACKAGE_VERSION" ]; then |
| 131 | + echo "ERROR: Failed to get the package version" |
| 132 | + exit 1 |
| 133 | + fi |
| 134 | +
|
| 135 | + # Build the wasm file name |
| 136 | + WASM_FILE_NAME="${PACKAGE_NAME}_v${PACKAGE_VERSION}.wasm" |
| 137 | +
|
| 138 | + # Navigate to the output directory |
| 139 | + cd ${OUTPUT} |
| 140 | +
|
| 141 | + # Find the .wasm file and copy it as unoptimized.wasm for hash calculation |
| 142 | + find ${OUTPUT} -name "*.wasm" -exec cp {} ${WASM_FILE_NAME} \; |
| 143 | + stellar contract optimize --wasm ${WASM_FILE_NAME} --wasm-out ${WASM_FILE_NAME} |
| 144 | +
|
| 145 | + # Calculate the hash of the wasm file |
| 146 | + WASM_HASH=$(sha256sum $WASM_FILE_NAME | cut -d ' ' -f 1) |
| 147 | +
|
| 148 | + # Set environment variables |
| 149 | + echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_ENV |
| 150 | + echo "WASM_FILE_NAME=$WASM_FILE_NAME" >> $GITHUB_ENV |
| 151 | + echo "WASM_HASH=$WASM_HASH" >> $GITHUB_ENV |
| 152 | + echo "PACKAGE_NAME=$PACKAGE_NAME" >> $GITHUB_ENV |
| 153 | + echo "BUILD_INFO=$BUILD_INFO" >> $GITHUB_ENV |
| 154 | +
|
| 155 | + - name: Build release name |
| 156 | + run: | |
| 157 | + CLI_VERSION=$(stellar --version | grep -oP 'stellar \K\S+') |
| 158 | + if [ -n "${{ inputs.relative_path }}" ]; then |
| 159 | + relative_path=$(echo "_${{ inputs.relative_path }}" | sed 's/\W\+/_/g') |
| 160 | + fi |
| 161 | +
|
| 162 | + # Check if the release_name input is equal to PACKAGE_VERSION |
| 163 | + if [ "${{ inputs.release_name }}" != "${PACKAGE_VERSION}" ] && [ "${{ inputs.release_name }}" != "v${PACKAGE_VERSION}" ]; then |
| 164 | + pkg_version="_pkg${PACKAGE_VERSION}" |
| 165 | + else |
| 166 | + pkg_version="" |
| 167 | + fi |
| 168 | +
|
| 169 | + TAG_NAME="${{ inputs.release_name }}" |
| 170 | + echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV |
| 171 | +
|
| 172 | + - name: Create release |
| 173 | + working-directory: ${{ env.OUTPUT }} |
| 174 | + env: |
| 175 | + GH_TOKEN: ${{ secrets.release_token }} |
| 176 | + run: | |
| 177 | + gh release create "${{ env.TAG_NAME }}" "${{ env.OUTPUT }}/${{ env.WASM_FILE_NAME }}" \ |
| 178 | + --title "${{ env.TAG_NAME }}" \ |
| 179 | + --notes "${{ inputs.release_description }}" |
| 180 | + shell: bash |
| 181 | + |
| 182 | + - name: Set up Node.js |
| 183 | + uses: actions/setup-node@v4 |
| 184 | + with: |
| 185 | + node-version: "14" |
| 186 | + |
| 187 | + - name: Build output |
| 188 | + run: | |
| 189 | + JSON_OUTPUT=$(node -e "console.log(JSON.stringify({ |
| 190 | + wasm: process.env.WASM, |
| 191 | + hash: process.env.HASH, |
| 192 | + relPath: (process.env.REL_PATH || undefined), |
| 193 | + package: (process.env.PACKAGE || undefined), |
| 194 | + make: (process.env.MAKE || undefined) |
| 195 | + }))") |
| 196 | + echo "WASM_OUTPUT='$JSON_OUTPUT'" >> $GITHUB_ENV |
| 197 | + env: |
| 198 | + REL_PATH: ${{ inputs.relative_path }} |
| 199 | + PACKAGE: ${{ inputs.package }} |
| 200 | + MAKE: ${{ inputs.make_target }} |
| 201 | + HASH: ${{ env.WASM_HASH }} |
| 202 | + WASM: ${{ env.WASM_FILE_NAME }} |
| 203 | + |
| 204 | + - name: Output WASM ${{ env.WASM_OUTPUT }} |
| 205 | + run: echo ${{ env.WASM_OUTPUT }} |
| 206 | + |
| 207 | + - name: Send release info |
| 208 | + run: | |
| 209 | + JSON_OBJECT=$(node -e "console.log(JSON.stringify({ |
| 210 | + repository: process.env.REPOSITORY, |
| 211 | + commitHash: process.env.COMMIT_HASH, |
| 212 | + jobId: process.env.JOB_ID, |
| 213 | + runId: process.env.RUN_ID, |
| 214 | + contractHash: process.env.CONTRACT_HASH, |
| 215 | + relativePath: process.env.RELATIVE_PATH || undefined, |
| 216 | + packageName: process.env.PACKAGE_NAME || undefined, |
| 217 | + makeTarget: process.env.MAKE_TARGET || undefined |
| 218 | + }))") |
| 219 | +
|
| 220 | + echo "JSON to send: $JSON_OBJECT" |
| 221 | +
|
| 222 | + curl -X POST "https://api.stellar.expert/explorer/public/contract-validation/match" \ |
| 223 | + -H "Content-Type: application/json" \ |
| 224 | + -d "$JSON_OBJECT" \ |
| 225 | + --max-time 15 |
| 226 | + env: |
| 227 | + REPOSITORY: ${{ github.server_url }}/${{ github.repository }} |
| 228 | + COMMIT_HASH: ${{ github.sha }} |
| 229 | + JOB_ID: ${{ github.job }} |
| 230 | + RUN_ID: ${{ github.run_id }} |
| 231 | + CONTRACT_HASH: ${{ env.WASM_HASH }} |
| 232 | + RELATIVE_PATH: ${{ inputs.relative_path }} |
| 233 | + PACKAGE_NAME: ${{ inputs.package }} |
| 234 | + MAKE_TARGET: ${{ inputs.make_target }} |
| 235 | + |
| 236 | + - name: Attest |
| 237 | + uses: actions/attest-build-provenance@v3 |
| 238 | + with: |
| 239 | + subject-path: "${{ env.OUTPUT }}/${{ env.WASM_FILE_NAME }}" |
| 240 | + subject-name: "${{ env.WASM_FILE_NAME }}" |
0 commit comments