Skip to content

Commit cb9b2da

Browse files
committed
Create a CRAN-like binary distribution repository.
Use a gh-pages branch for GitHub pages hosting of a CRAN-like repository. When a release is created, there is a workflow that automatically updates the CRAN-like repository using the information from the release assets. Note that the CRAN-like repository does not include the binary packages themselves, it forwards to the URLs of the release assets on GitHub.
1 parent 9cfc3bd commit cb9b2da

3 files changed

Lines changed: 372 additions & 20 deletions

File tree

.github/workflows/main.yml

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
fail-fast: false
2525
matrix:
2626
R: [ '4.4.3', '4.5.3', '4.6.0' ]
27-
os: [ 'macos-15-intel', 'ubuntu-latest', 'windows-latest']
27+
os: [ 'macos-15-intel', 'ubuntu-24.04', 'windows-latest']
2828
runs-on: ${{ matrix.os }}
2929
name: ${{ matrix.R }} ${{ matrix.os }} build
3030

@@ -66,44 +66,56 @@ jobs:
6666
env:
6767
ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS: 2
6868
run: |
69-
R -e "Sys.setenv(MAKEJ=2); remotes::install_git(c('.'), lib=Sys.getenv('R_LIBS_USER'))"
69+
R -e "Sys.setenv(MAKEJ=2); remotes::install_git(c('.'), lib=Sys.getenv('R_LIBS_USER'), upgrade='never', INSTALL_opts='--build')"
7070
R -e "library(SimpleITK); Version()"
71-
- name: Create binary package from installed package
72-
id: create_package
71+
- name: Rename package artifact
72+
# The original artifact name is SimpleITK_<sitk_version>.zip (windows),
73+
# SimpleITK_<sitk_version>.tgz (macOS), or SimpleITK_<sitk_version>.tar.gz (Linux).
74+
# This is irrespective of the R version. We need to rename them so that they are
75+
# unique. Otherwise we could not upload artifacts for different
76+
# R versions because the names collide.
77+
id: rename_package
7378
shell: bash
7479
run: |
75-
# Get the R version for naming
76-
R_VERSION_SHORT=$(echo "${{ matrix.R }}" | cut -d'.' -f1,2)
80+
# canonical approach to collecting build artifacts in a directory for upload
81+
mkdir -p artifacts
7782
78-
# Get package version from DESCRIPTION
79-
PKG_VERSION=$(Rscript -e "cat(read.dcf(file.path(Sys.getenv('R_LIBS_USER'), 'SimpleITK', 'DESCRIPTION'), 'Version')[1])")
83+
# remotes::install_git(..., INSTALL_opts='--build') writes a valid package
84+
# file into the current working directory (GITHUB_WORKSPACE).
85+
PKG_PATH=$(find "${GITHUB_WORKSPACE}" -maxdepth 1 -type f \
86+
\( -name 'SimpleITK_*.tgz' -o -name 'SimpleITK_*.zip' -o -name 'SimpleITK_*.tar.gz' \) \
87+
| head -n 1)
8088
81-
# Create output directory for artifacts
82-
mkdir -p artifacts
89+
if [[ -z "${PKG_PATH}" ]]; then
90+
echo "No built package artifact found in ${GITHUB_WORKSPACE}."
91+
exit 1
92+
fi
93+
94+
# package naming is SimpleITK_${PKG_VERSION}_R${R_VERSION_SHORT}_${OS_ARCHIVE_EXT}
95+
R_VERSION_SHORT=$(echo "${{ matrix.R }}" | cut -d'.' -f1,2)
96+
PKG_VERSION=$(Rscript -e "cat(read.dcf('DESCRIPTION', 'Version')[1])")
8397
84-
# Create binary package archive from installed package (no recompilation)
85-
cd "${R_LIBS_USER}"
8698
if [[ "$RUNNER_OS" == "macOS" ]]; then
8799
PKG_NAME="SimpleITK_${PKG_VERSION}_R${R_VERSION_SHORT}_macos-x86_64.tgz"
88-
tar czf "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}" SimpleITK
89100
elif [[ "$RUNNER_OS" == "Linux" ]]; then
90101
PKG_NAME="SimpleITK_${PKG_VERSION}_R${R_VERSION_SHORT}_linux-x86_64.tar.gz"
91-
tar czf "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}" SimpleITK
92102
elif [[ "$RUNNER_OS" == "Windows" ]]; then
93103
PKG_NAME="SimpleITK_${PKG_VERSION}_R${R_VERSION_SHORT}_windows-x86_64.zip"
94-
7z a -tzip "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}" SimpleITK
104+
else
105+
echo "Unsupported OS: $RUNNER_OS"
106+
exit 1
95107
fi
96108
97-
cd "${GITHUB_WORKSPACE}"
109+
mv "${PKG_PATH}" "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}"
98110
ls -lh artifacts/
99111
100112
# Export PKG_NAME as output for use in upload step
101113
echo "pkg_name=${PKG_NAME}" >> $GITHUB_OUTPUT
102114
- name: Upload binary package
103-
if: steps.create_package.outcome == 'success'
115+
if: steps.rename_package.outcome == 'success'
104116
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
105117
with:
106-
name: ${{ steps.create_package.outputs.pkg_name }}
118+
name: ${{ steps.rename_package.outputs.pkg_name }}
107119
path: artifacts/*
108120
retention-days: 30
109121

@@ -161,8 +173,43 @@ jobs:
161173
draft: true
162174
name: SimpleITK ${{ github.ref_name }} R Package Release
163175
body: |
164-
Please review and test the packages before publishing this release.
165-
Then remove the "Draft" status to make it public and delete this message.
176+
**Please review and test the packages before publishing this release. Then remove this line and make it public.**
177+
178+
Detailed release notes are available on the [main SimpleITK repository](https://github.com/SimpleITK/SimpleITK/releases/${{ github.ref_name }}).
179+
180+
The GitHub Pages repository provides platform-specific binaries. If a binary is not available, you will need to build SimpleITK locally using the remotes installer. See the [README](https://github.com/${{ github.repository }}/blob/main/README.md) for detailed instructions.
181+
182+
Windows and macOS:
183+
184+
```r
185+
install.packages(
186+
"SimpleITK",
187+
repos = c("https://simpleitk.github.io/SimpleITKRInstaller/${{ github.ref_name }}"),
188+
type = "binary"
189+
)
190+
```
191+
192+
Linux:
193+
194+
```r
195+
install.packages(
196+
"SimpleITK",
197+
repos = NULL,
198+
contriburl = paste0(
199+
"https://simpleitk.github.io/SimpleITKRInstaller/${{ github.ref_name }}/__linux__/ubuntu-noble/",
200+
paste(R.version$major, sub("\\..*$", "", R.version$minor), sep = "."),
201+
"/src/contrib"
202+
),
203+
type = "source"
204+
)
205+
```
206+
207+
The Linux install above uses a "source" type installation even though it is binary, due to the way R handles binary packages on this platform.
208+
209+
If for some reason you decided to download the package artifact from this release page, before you install the package you will need to first unzip the file. Then rename it to SimpleITK_<version>.zip (windows), SimpleITK_<version>.tgz (macOS), or SimpleITK_<version>.tar.gz (Linux) to match the expected file name format.
210+
211+
```r
212+
166213
files: |
167214
release-artifacts/*
168215
fail_on_unmatched_files: true
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Update CRAN Repository
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: write
9+
10+
concurrency:
11+
group: update-cran-repository
12+
cancel-in-progress: false
13+
14+
jobs:
15+
update-repo:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
20+
with:
21+
fetch-depth: 0
22+
ref: main
23+
24+
- name: Set up R
25+
uses: r-lib/actions/setup-r@a51a8012b0aab7c32ef9d19bf54da93f3254335e # v2.12.0
26+
27+
- name: Download Release Assets
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
run: |
31+
mkdir -p temp_packages
32+
gh release download ${{ github.event.release.tag_name }} --dir temp_packages
33+
34+
- name: Route Assets and Build PACKAGES Files
35+
shell: bash
36+
run: |
37+
# Run the R script and always do the cleanup of the temp_packages directory,
38+
# step returns the exit code from the R script.
39+
(
40+
Rscript update_cran_repo.R \
41+
--packages_dir temp_packages \
42+
--base_cran_dir . \
43+
--repo_url https://github.com/${{ github.repository }} \
44+
--tag ${{ github.event.release.tag_name }}
45+
status=$?
46+
rm -rf temp_packages
47+
exit $status
48+
)
49+
50+
- name: Commit and Push Changes
51+
run: |
52+
git config --global user.name "github-actions[bot]"
53+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
54+
git checkout gh-pages
55+
git add .
56+
if ! git diff --cached --quiet; then
57+
git commit -m "Update CRAN repository index for release ${{ github.event.release.tag_name }}"
58+
git push
59+
fi

0 commit comments

Comments
 (0)