|
| 1 | +<div align="center"> |
| 2 | + <h1>fingerprint</h1> |
| 3 | + <p>Checking project fingerprinting for pull requests using <a href="https://www.npmjs.com/package/@expo/fingerprint"><code>@expo/fingerprint</code></a></p> |
| 4 | +</div> |
| 5 | + |
| 6 | +<p align="center"> |
| 7 | + <a href="https://github.com/expo/expo-github-action/releases" title="Latest release"> |
| 8 | + <picture> |
| 9 | + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/package-json/v/expo/expo-github-action?style=flat-square&color=0366D6&labelColor=49505A"> |
| 10 | + <img alt="Latest release" src="https://img.shields.io/github/package-json/v/expo/expo-github-action?style=flat-square&color=0366D6&labelColor=D1D5DA" /> |
| 11 | + </picture> |
| 12 | + </a> |
| 13 | + <a href="https://github.com/expo/expo-github-action/actions" title="Workflow status"> |
| 14 | + <picture> |
| 15 | + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/expo/expo-github-action/test.yml?branch=main&style=flat-square&labelColor=49505A"> |
| 16 | + <img alt="Workflow status" src="https://img.shields.io/github/actions/workflow/status/expo/expo-github-action/test.yml?branch=main&style=flat-square&labelColor=D1D5DA" /> |
| 17 | + </picture> |
| 18 | + </a> |
| 19 | +</p> |
| 20 | + |
| 21 | +<p align="center"> |
| 22 | + <a href="#usage"><b>Usage</b></a> |
| 23 | + — |
| 24 | + <a href="#available-outputs"><b>Outputs</b></a> |
| 25 | + — |
| 26 | + <a href="#example-workflows"><b>Examples</b></a> |
| 27 | + — |
| 28 | + <a href="#caveats"><b>Caveats</b></a> |
| 29 | + — |
| 30 | + <a href="https://github.com/expo/expo-github-action/blob/main/CHANGELOG.md"><b>Changelog</b></a> |
| 31 | +</p> |
| 32 | + |
| 33 | +<br /> |
| 34 | + |
| 35 | +> **Warning** |
| 36 | +> This sub action is experimental and might change without notice. Use it at your own risk |
| 37 | +
|
| 38 | +## Overview |
| 39 | + |
| 40 | +`fingerprint` is a GitHub Action that checks project fingerprinting for pull requests using [`@expo/fingerprint`](https://www.npmjs.com/package/@expo/fingerprint). When a pull request is updated, you can use this action to check the fingerprint integrity. If a pull request is fingerprint compatible, it means there are no changes from native code and be Over-The-Air updates compatible. Otherwise, if fingerprint changed, it means the project has native code changes. |
| 41 | + |
| 42 | +This action is designed to be used in conjunction with the `@expo/fingerprint` package, which generates a unique fingerprint for each pull request based on the contents of the code. By using fingerprinting, this action can determine if a pull request has already been built, and reuse the existing build instead of creating a new one. |
| 43 | + |
| 44 | +## Usage |
| 45 | + |
| 46 | +To use this action, add the following code to your workflow: |
| 47 | + |
| 48 | +```yaml |
| 49 | +on: |
| 50 | + push: |
| 51 | + # REQUIRED: push main(default) branch is necessary for this action to update its fingerprint database |
| 52 | + branches: [main] |
| 53 | + pull_request: |
| 54 | + types: [opened, synchronize] |
| 55 | + |
| 56 | +jobs: |
| 57 | + <JOB_NAME>: |
| 58 | + runs-on: <RUNNER> |
| 59 | + # REQUIRED: limit concurrency when pushing main(default) branch to prevent conflict for this action to update its fingerprint database |
| 60 | + concurrency: fingerprint-${{ github.event_name != 'pull_request' && 'main' || github.run_id }} |
| 61 | + permissions: |
| 62 | + # REQUIRED: Allow comments of PRs |
| 63 | + pull-requests: write # Allow comments on PRs |
| 64 | + # REQUIRED: Allow updating fingerprint in acton caches |
| 65 | + actions: write |
| 66 | + |
| 67 | + steps: |
| 68 | + - name: Check fingerprint |
| 69 | + uses: expo/expo-github-action/fingerprint@main |
| 70 | +``` |
| 71 | +
|
| 72 | +### Configuration options |
| 73 | +
|
| 74 | +This action is customizable through variables defined in the [`action.yml`](action.yml). |
| 75 | +Here is a summary of all the input options you can use. |
| 76 | + |
| 77 | +| variable | default | description | |
| 78 | +| ---------------------------------- | ---------------- | ----------------------------------------------------------------------- | |
| 79 | +| **working-directory** | - | The relative directory of your Expo app | |
| 80 | +| **packager** | `yarn` | The package manager used to install the fingerprint tools | |
| 81 | +| **github-token** | `github.token` | GitHub token to use when commenting on PR ([read more](#github-tokens)) | |
| 82 | +| **fingerprint-version** | `latest` | `@expo/fingerprint` version to install | |
| 83 | +| **fingerprint-installation-cache** | `true` | If the `@expo/fingerprint` should be cached to speed up installation | |
| 84 | +| **fingerprint-db-cache-key** | `fingerprint-db` | A cache key to use for saving the fingerprint database | |
| 85 | + |
| 86 | +And the action will generate these [outputs](#available-outputs) for other actions to do something based on current project fingerprint |
| 87 | + |
| 88 | +### Available outputs |
| 89 | + |
| 90 | +In case you want to reuse this action for other purpose, this action will set the following action outputs. |
| 91 | + |
| 92 | +| output name | description | |
| 93 | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 94 | +| **fingerprint-diff** | The diff between the current and the previous fingerprint. It is a JSON array of fingerprint diff. If the fingerprint does not change in between, the result diff will be an empty array `[]` | |
| 95 | + |
| 96 | +## Example workflows |
| 97 | + |
| 98 | +Here's an example workflow that uses this action to comment pull requests and add `Fingerprint:compatible` and `Fingerprint:changed` labels |
| 99 | + |
| 100 | +```yaml |
| 101 | +name: PR Labeler |
| 102 | +
|
| 103 | +on: |
| 104 | + push: |
| 105 | + # REQUIRED: push main(default) branch is necessary for this action to update its fingerprint database |
| 106 | + branches: [main] |
| 107 | + pull_request: |
| 108 | + types: [opened, synchronize] |
| 109 | +
|
| 110 | +jobs: |
| 111 | + fingerprint: |
| 112 | + runs-on: ubuntu-latest |
| 113 | + # REQUIRED: limit concurrency when pushing main(default) branch to prevent conflict for this action to update its fingerprint database |
| 114 | + concurrency: fingerprint-${{ github.event_name != 'pull_request' && 'main' || github.run_id }} |
| 115 | + permissions: |
| 116 | + # REQUIRED: Allow comments of PRs |
| 117 | + pull-requests: write # Allow comments on PRs |
| 118 | + # REQUIRED: Allow updating fingerprint in acton caches |
| 119 | + actions: write |
| 120 | +
|
| 121 | + steps: |
| 122 | + - name: 🏗 Setup repo |
| 123 | + uses: actions/checkout@v3 |
| 124 | +
|
| 125 | + - name: 🏗 Setup Node |
| 126 | + uses: actions/setup-node@v3 |
| 127 | + with: |
| 128 | + node-version: 18.x |
| 129 | + cache: yarn |
| 130 | +
|
| 131 | + - name: 📦 Install dependencies |
| 132 | + run: yarn install |
| 133 | +
|
| 134 | + - name: Check fingerprint |
| 135 | + id: fingerprint |
| 136 | + uses: expo/expo-github-action/preview-build@main |
| 137 | +
|
| 138 | + - uses: actions/github-script@v6 |
| 139 | + if: ${{ github.event_name == 'pull_request' && github.steps.fingerprint.outputs.fingerprint-diff == '[]' }} |
| 140 | + with: |
| 141 | + script: | |
| 142 | + try { |
| 143 | + await github.rest.issues.removeLabel({ |
| 144 | + issue_number: context.issue.number, |
| 145 | + owner: context.repo.owner, |
| 146 | + repo: context.repo.repo, |
| 147 | + name: ['Fingerprint:changed'] |
| 148 | + }) |
| 149 | + } catch (e) { |
| 150 | + if (e.status != 404) { |
| 151 | + throw e; |
| 152 | + } |
| 153 | + } |
| 154 | + github.rest.issues.addLabels({ |
| 155 | + issue_number: context.issue.number, |
| 156 | + owner: context.repo.owner, |
| 157 | + repo: context.repo.repo, |
| 158 | + labels: ['Fingerprint:compatible'] |
| 159 | + }) |
| 160 | +
|
| 161 | + - uses: actions/github-script@v6 |
| 162 | + if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.fingerprint-diff != '[]' }} |
| 163 | + with: |
| 164 | + script: | |
| 165 | + try { |
| 166 | + await github.rest.issues.removeLabel({ |
| 167 | + issue_number: context.issue.number, |
| 168 | + owner: context.repo.owner, |
| 169 | + repo: context.repo.repo, |
| 170 | + name: ['Fingerprint:compatible'] |
| 171 | + }) |
| 172 | + } catch (e) { |
| 173 | + if (e.status != 404) { |
| 174 | + throw e; |
| 175 | + } |
| 176 | + } |
| 177 | + github.rest.issues.addLabels({ |
| 178 | + issue_number: context.issue.number, |
| 179 | + owner: context.repo.owner, |
| 180 | + repo: context.repo.repo, |
| 181 | + labels: ['Fingerprint:changed'] |
| 182 | + }) |
| 183 | +``` |
| 184 | + |
| 185 | +This workflow listens for pull request events and generates a fingerprint for each pull request. Based on the `fingerprint-diff` output, the example then use GitHub API to add/remove labels based on fingerprint compatible state. |
| 186 | + |
| 187 | +## Caveats |
| 188 | + |
| 189 | +### GitHub tokens |
| 190 | + |
| 191 | +When using the GitHub API, you always need to be authenticated. |
| 192 | +This action tries to auto-authenticate using the [Automatic token authentication][link-gha-token] from GitHub. |
| 193 | +You can overwrite the token by adding the `GITHUB_TOKEN` environment variable or add the **github-token** input. |
| 194 | + |
| 195 | +<div align="center"> |
| 196 | + <br /> |
| 197 | + with :heart: <strong>Expo</strong> |
| 198 | + <br /> |
| 199 | +</div> |
0 commit comments