|
4 | 4 | # CI that:
|
5 | 5 | #
|
6 | 6 | # * checks for a Git Tag that looks like a release
|
7 |
| -# * creates a draft Github Release™ and fills in its text |
8 |
| -# * builds artifacts with cargo-dist (executable-zips, installers, hashes) |
9 |
| -# * uploads those artifacts to the Github Release™ |
10 |
| -# * undrafts the Github Release™ on success |
| 7 | +# * builds artifacts with cargo-dist (archives, installers, hashes) |
| 8 | +# * uploads those artifacts to temporary workflow zip |
| 9 | +# * on success, uploads the artifacts to a Github Release™ |
11 | 10 | #
|
12 |
| -# Note that the Github Release™ will be created before the artifacts, |
13 |
| -# so there will be a few minutes where the release has no artifacts |
14 |
| -# and then they will slowly trickle in, possibly failing. To make |
15 |
| -# this more pleasant we mark the release as a "draft" until all |
16 |
| -# artifacts have been successfully uploaded. This allows you to |
17 |
| -# choose what to do with partial successes and avoids spamming |
18 |
| -# anyone with notifications before the release is actually ready. |
| 11 | +# Note that the Github Release™ will be created with a generated |
| 12 | +# title/body based on your changelogs. |
19 | 13 | name: Release
|
20 | 14 |
|
21 | 15 | permissions:
|
@@ -46,132 +40,152 @@ on:
|
46 | 40 | push:
|
47 | 41 | tags:
|
48 | 42 | - '**[0-9]+.[0-9]+.[0-9]+*'
|
| 43 | + pull_request: |
49 | 44 |
|
50 | 45 | jobs:
|
51 | 46 | # Run 'cargo dist plan' to determine what tasks we need to do
|
52 |
| - # and create a draft github release with the computed title/body |
53 | 47 | plan:
|
54 | 48 | runs-on: ubuntu-latest
|
55 | 49 | outputs:
|
56 |
| - has-releases: ${{ steps.plan.outputs.has-releases }} |
57 |
| - releases: ${{ steps.plan.outputs.releases }} |
| 50 | + val: ${{ steps.plan.outputs.manifest }} |
| 51 | + tag: ${{ !github.event.pull_request && github.ref_name || '' }} |
| 52 | + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} |
| 53 | + publishing: ${{ !github.event.pull_request }} |
58 | 54 | env:
|
59 | 55 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
60 | 56 | steps:
|
61 |
| - - uses: actions/checkout@v3 |
| 57 | + - uses: actions/checkout@v4 |
62 | 58 | with:
|
63 | 59 | submodules: recursive
|
64 | 60 | - name: Install cargo-dist
|
65 |
| - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" |
| 61 | + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.3.1/cargo-dist-installer.sh | sh" |
66 | 62 | - id: plan
|
67 | 63 | run: |
|
68 |
| - cargo dist plan --tag=${{ github.ref_name }} --output-format=json > dist-manifest.json |
69 |
| - echo "dist plan ran successfully" |
| 64 | + cargo dist plan ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} --output-format=json > dist-manifest.json |
| 65 | + echo "cargo dist plan ran successfully" |
70 | 66 | cat dist-manifest.json
|
71 |
| -
|
72 |
| - # Create the Github Release™ based on what cargo-dist thinks it should be |
73 |
| - ANNOUNCEMENT_TITLE=$(jq --raw-output ".announcement_title" dist-manifest.json) |
74 |
| - IS_PRERELEASE=$(jq --raw-output ".announcement_is_prerelease" dist-manifest.json) |
75 |
| - jq --raw-output ".announcement_github_body" dist-manifest.json > new_dist_announcement.md |
76 |
| - gh release create ${{ github.ref_name }} --draft --prerelease="$IS_PRERELEASE" --title="$ANNOUNCEMENT_TITLE" --notes-file=new_dist_announcement.md |
77 |
| - echo "created announcement!" |
78 |
| -
|
79 |
| - # Upload the manifest to the Github Release™ |
80 |
| - gh release upload ${{ github.ref_name }} dist-manifest.json |
81 |
| - echo "uploaded manifest!" |
82 |
| -
|
83 |
| - # Disable all the upload-artifacts tasks if we have no actual releases |
84 |
| - HAS_RELEASES=$(jq --raw-output ".releases != null" dist-manifest.json) |
85 |
| - echo "has-releases=$HAS_RELEASES" >> "$GITHUB_OUTPUT" |
86 |
| - echo "releases=$(jq --compact-output ".releases" dist-manifest.json)" >> "$GITHUB_OUTPUT" |
| 67 | + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" |
| 68 | + - name: "Upload dist-manifest.json" |
| 69 | + uses: actions/upload-artifact@v3 |
| 70 | + with: |
| 71 | + name: artifacts |
| 72 | + path: dist-manifest.json |
87 | 73 |
|
88 | 74 | # Build and packages all the platform-specific things
|
89 | 75 | upload-local-artifacts:
|
90 | 76 | # Let the initial task tell us to not run (currently very blunt)
|
91 | 77 | needs: plan
|
92 |
| - if: ${{ needs.plan.outputs.has-releases == 'true' }} |
| 78 | + if: ${{ fromJson(needs.plan.outputs.val).releases != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} |
93 | 79 | strategy:
|
94 | 80 | fail-fast: false
|
95 |
| - matrix: |
96 |
| - # For these target platforms |
97 |
| - include: |
98 |
| - - os: "macos-11" |
99 |
| - dist-args: "--artifacts=local --target=aarch64-apple-darwin" |
100 |
| - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" |
101 |
| - - os: "macos-11" |
102 |
| - dist-args: "--artifacts=local --target=x86_64-apple-darwin" |
103 |
| - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" |
104 |
| - - os: "ubuntu-20.04" |
105 |
| - dist-args: "--artifacts=local --target=x86_64-unknown-linux-gnu" |
106 |
| - install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" |
107 |
| - runs-on: ${{ matrix.os }} |
| 81 | + # Target platforms/runners are computed by cargo-dist in create-release. |
| 82 | + # Each member of the matrix has the following arguments: |
| 83 | + # |
| 84 | + # - runner: the github runner |
| 85 | + # - dist-args: cli flags to pass to cargo dist |
| 86 | + # - install-dist: expression to run to install cargo-dist on the runner |
| 87 | + # |
| 88 | + # Typically there will be: |
| 89 | + # - 1 "global" task that builds universal installers |
| 90 | + # - N "local" tasks that build each platform's binaries and platform-specific installers |
| 91 | + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} |
| 92 | + runs-on: ${{ matrix.runner }} |
108 | 93 | env:
|
109 | 94 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
110 | 95 | steps:
|
111 |
| - - uses: actions/checkout@v3 |
| 96 | + - uses: actions/checkout@v4 |
112 | 97 | with:
|
113 | 98 | submodules: recursive
|
| 99 | + - uses: swatinem/rust-cache@v2 |
114 | 100 | - name: Install cargo-dist
|
115 |
| - run: ${{ matrix.install-dist }} |
116 |
| - - name: Run cargo-dist |
117 |
| - # This logic is a bit janky because it's trying to be a polyglot between |
118 |
| - # powershell and bash since this will run on windows, macos, and linux! |
119 |
| - # The two platforms don't agree on how to talk about env vars but they |
120 |
| - # do agree on 'cat' and '$()' so we use that to marshal values between commands. |
| 101 | + run: ${{ matrix.install_dist }} |
| 102 | + - name: Build artifacts |
121 | 103 | run: |
|
122 | 104 | # Actually do builds and make zips and whatnot
|
123 |
| - cargo dist build --tag=${{ github.ref_name }} --output-format=json ${{ matrix.dist-args }} > dist-manifest.json |
124 |
| - echo "dist ran successfully" |
125 |
| - cat dist-manifest.json |
126 |
| -
|
| 105 | + cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json ${{ matrix.dist_args }} > dist-manifest.json |
| 106 | + echo "cargo dist ran successfully" |
| 107 | + - id: cargo-dist |
| 108 | + name: Post-build |
| 109 | + # We force bash here just because github makes it really hard to get values up |
| 110 | + # to "real" actions without writing to env-vars, and writing to env-vars has |
| 111 | + # inconsistent syntax between shell and powershell. |
| 112 | + shell: bash |
| 113 | + run: | |
127 | 114 | # Parse out what we just built and upload it to the Github Release™
|
128 |
| - jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt |
129 |
| - echo "uploading..." |
130 |
| - cat uploads.txt |
131 |
| - gh release upload ${{ github.ref_name }} $(cat uploads.txt) |
132 |
| - echo "uploaded!" |
| 115 | + echo "paths<<EOF" >> "$GITHUB_OUTPUT" |
| 116 | + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" |
| 117 | + echo "EOF" >> "$GITHUB_OUTPUT" |
| 118 | + - name: "Upload artifacts" |
| 119 | + uses: actions/upload-artifact@v3 |
| 120 | + with: |
| 121 | + name: artifacts |
| 122 | + path: ${{ steps.cargo-dist.outputs.paths }} |
133 | 123 |
|
134 | 124 | # Build and package all the platform-agnostic(ish) things
|
135 | 125 | upload-global-artifacts:
|
136 |
| - needs: upload-local-artifacts |
| 126 | + needs: [plan, upload-local-artifacts] |
137 | 127 | runs-on: "ubuntu-20.04"
|
138 | 128 | env:
|
139 | 129 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
140 | 130 | steps:
|
141 |
| - - uses: actions/checkout@v3 |
| 131 | + - uses: actions/checkout@v4 |
142 | 132 | with:
|
143 | 133 | submodules: recursive
|
144 | 134 | - name: Install cargo-dist
|
145 |
| - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.2.0/cargo-dist-installer.sh | sh" |
| 135 | + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.3.1/cargo-dist-installer.sh | sh" |
146 | 136 | # Get all the local artifacts for the global tasks to use (for e.g. checksums)
|
147 | 137 | - name: Fetch local artifacts
|
| 138 | + uses: actions/download-artifact@v3 |
| 139 | + with: |
| 140 | + name: artifacts |
| 141 | + path: target/distrib/ |
| 142 | + - id: cargo-dist |
| 143 | + shell: bash |
148 | 144 | run: |
|
149 |
| - gh release download ${{ github.ref_name }} --dir target/distrib/ |
150 |
| - - name: Run cargo-dist |
151 |
| - run: | |
152 |
| - cargo dist build --tag=${{ github.ref_name }} --output-format=json "--artifacts=global" > dist-manifest.json |
153 |
| - echo "dist ran successfully" |
154 |
| - cat dist-manifest.json |
| 145 | + cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json |
| 146 | + echo "cargo dist ran successfully" |
155 | 147 |
|
156 | 148 | # Parse out what we just built and upload it to the Github Release™
|
157 |
| - jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt |
158 |
| - echo "uploading..." |
159 |
| - cat uploads.txt |
160 |
| - gh release upload ${{ github.ref_name }} $(cat uploads.txt) |
161 |
| - echo "uploaded!" |
| 149 | + echo "paths<<EOF" >> "$GITHUB_OUTPUT" |
| 150 | + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" |
| 151 | + echo "EOF" >> "$GITHUB_OUTPUT" |
| 152 | + - name: "Upload artifacts" |
| 153 | + uses: actions/upload-artifact@v3 |
| 154 | + with: |
| 155 | + name: artifacts |
| 156 | + path: ${{ steps.cargo-dist.outputs.paths }} |
162 | 157 |
|
163 |
| - # Mark the Github Release™ as a non-draft now that everything has succeeded! |
| 158 | + should-publish: |
| 159 | + needs: |
| 160 | + - plan |
| 161 | + - upload-local-artifacts |
| 162 | + - upload-global-artifacts |
| 163 | + if: ${{ needs.plan.outputs.publishing == 'true' }} |
| 164 | + runs-on: ubuntu-latest |
| 165 | + steps: |
| 166 | + - name: print tag |
| 167 | + run: echo "ok we're publishing!" |
| 168 | + |
| 169 | + # Create a Github Release with all the results once everything is done, |
164 | 170 | publish-release:
|
165 |
| - # Only run after all the other tasks, but it's ok if upload-artifacts was skipped |
166 |
| - needs: [plan, upload-local-artifacts, upload-global-artifacts] |
167 |
| - if: ${{ always() && needs.plan.result == 'success' && (needs.upload-local-artifacts.result == 'skipped' || needs.upload-local-artifacts.result == 'success') && (needs.upload-global-artifacts.result == 'skipped' || needs.upload-global-artifacts.result == 'success') }} |
| 171 | + needs: [plan, should-publish] |
168 | 172 | runs-on: ubuntu-latest
|
169 | 173 | env:
|
170 | 174 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
171 | 175 | steps:
|
172 |
| - - uses: actions/checkout@v3 |
| 176 | + - uses: actions/checkout@v4 |
173 | 177 | with:
|
174 | 178 | submodules: recursive
|
175 |
| - - name: mark release as non-draft |
176 |
| - run: | |
177 |
| - gh release edit ${{ github.ref_name }} --draft=false |
| 179 | + - name: "Download artifacts" |
| 180 | + uses: actions/download-artifact@v3 |
| 181 | + with: |
| 182 | + name: artifacts |
| 183 | + path: artifacts |
| 184 | + - name: Create Release |
| 185 | + uses: ncipollo/release-action@v1 |
| 186 | + with: |
| 187 | + tag: ${{ needs.plan.outputs.tag }} |
| 188 | + name: ${{ fromJson(needs.plan.outputs.val).announcement_title }} |
| 189 | + body: ${{ fromJson(needs.plan.outputs.val).announcement_github_body }} |
| 190 | + prerelease: ${{ fromJson(needs.plan.outputs.val).announcement_is_prerelease }} |
| 191 | + artifacts: "artifacts/*" |
0 commit comments