release.yml

  1name: Release
  2
  3on:
  4  workflow_dispatch:
  5
  6permissions:
  7  contents: write # to create releases, tags and upload assets
  8  pull-requests: read # to read pull request titles and labels for changelog
  9  id-token: write # to sign the release
 10
 11jobs:
 12  goreleaser:
 13    runs-on: macos-latest
 14    steps:
 15      - name: Checkout
 16        uses: actions/checkout@v6
 17        with:
 18          fetch-depth: 0
 19
 20      - name: Set up Go
 21        uses: actions/setup-go@v6
 22        with:
 23          go-version: "1.26.4"
 24
 25      - name: Set up Zig
 26        uses: goto-bus-stop/setup-zig@v2
 27
 28      - name: Bump version and push tag
 29        id: tag_version
 30        uses: mathieudutour/github-tag-action@v6.2
 31        with:
 32          github_token: ${{ secrets.GITHUB_TOKEN }}
 33
 34      - name: Fetch the new tag
 35        run: git fetch --tags
 36        env:
 37          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 38
 39      - name: Set up libpcsclite for Linux cross-compilation
 40        run: |
 41          PCSC_DIR="$RUNNER_TEMP/pcsclite"
 42          mkdir -p "$PCSC_DIR/include" "$PCSC_DIR/lib/pkgconfig"
 43
 44          # Download pcsc-lite headers from upstream
 45          PCSC_URL="https://raw.githubusercontent.com/LudovicRousseau/PCSC/master/src/PCSC"
 46          for header in winscard.h wintypes.h; do
 47            curl -fsSL "$PCSC_URL/$header" -o "$PCSC_DIR/include/$header"
 48          done
 49          # pcsclite.h is generated from pcsclite.h.in — download and substitute the version placeholder
 50          curl -fsSL "$PCSC_URL/pcsclite.h.in" -o "$PCSC_DIR/include/pcsclite.h"
 51          sed -i '' 's/@VERSION@/1.9.0/' "$PCSC_DIR/include/pcsclite.h"
 52
 53          # Build stub library — the real libpcsclite is loaded at runtime on the user's system,
 54          # but the linker needs symbols to resolve during cross-compilation.
 55          cat > "$RUNNER_TEMP/pcsclite_stub.c" << 'STUB'
 56          #include <stddef.h>
 57          typedef long LONG;
 58          typedef unsigned long DWORD;
 59          typedef void *LPCVOID;
 60          typedef char *LPSTR;
 61          typedef const char *LPCSTR;
 62          typedef unsigned char *LPBYTE;
 63          typedef unsigned char BYTE;
 64          typedef LONG SCARDCONTEXT;
 65          typedef LONG SCARDHANDLE;
 66          typedef struct { DWORD dwProtocol; DWORD cbPciLength; } SCARD_IO_REQUEST;
 67          typedef struct { LPCSTR szReader; DWORD dwCurrentState; DWORD dwEventState; DWORD cbAtr; unsigned char rgbAtr[36]; void *pvUserData; } SCARD_READERSTATE;
 68          LONG SCardEstablishContext(DWORD s, LPCVOID r1, LPCVOID r2, SCARDCONTEXT *c) { return 0; }
 69          LONG SCardReleaseContext(SCARDCONTEXT c) { return 0; }
 70          LONG SCardIsValidContext(SCARDCONTEXT c) { return 0; }
 71          LONG SCardCancel(SCARDCONTEXT c) { return 0; }
 72          LONG SCardConnect(SCARDCONTEXT c, LPCSTR r, DWORD s, DWORD p, SCARDHANDLE *h, DWORD *ap) { return 0; }
 73          LONG SCardReconnect(SCARDHANDLE h, DWORD s, DWORD p, DWORD d, DWORD *ap) { return 0; }
 74          LONG SCardDisconnect(SCARDHANDLE h, DWORD d) { return 0; }
 75          LONG SCardBeginTransaction(SCARDHANDLE h) { return 0; }
 76          LONG SCardEndTransaction(SCARDHANDLE h, DWORD d) { return 0; }
 77          LONG SCardStatus(SCARDHANDLE h, LPSTR r, DWORD *rl, DWORD *s, DWORD *p, LPBYTE a, DWORD *al) { return 0; }
 78          LONG SCardTransmit(SCARDHANDLE h, const SCARD_IO_REQUEST *si, const BYTE *s, DWORD sl, SCARD_IO_REQUEST *ri, BYTE *r, DWORD *rl) { return 0; }
 79          LONG SCardControl(SCARDHANDLE h, DWORD c, LPCVOID i, DWORD il, void *o, DWORD ol, DWORD *br) { return 0; }
 80          LONG SCardGetAttrib(SCARDHANDLE h, DWORD a, LPBYTE b, DWORD *bl) { return 0; }
 81          LONG SCardSetAttrib(SCARDHANDLE h, DWORD a, const BYTE *b, DWORD bl) { return 0; }
 82          LONG SCardListReaders(SCARDCONTEXT c, LPCSTR g, LPSTR r, DWORD *rl) { return 0; }
 83          LONG SCardListReaderGroups(SCARDCONTEXT c, LPSTR g, DWORD *gl) { return 0; }
 84          LONG SCardGetStatusChange(SCARDCONTEXT c, DWORD t, SCARD_READERSTATE *s, DWORD n) { return 0; }
 85          LONG SCardFreeMemory(SCARDCONTEXT c, LPCVOID m) { return 0; }
 86          const char *pcsc_stringify_error(LONG e) { return "stub"; }
 87          STUB
 88
 89          zig cc -c -target x86_64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_amd64.o" "$RUNNER_TEMP/pcsclite_stub.c"
 90          zig cc -c -target aarch64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_arm64.o" "$RUNNER_TEMP/pcsclite_stub.c"
 91
 92          mkdir -p "$PCSC_DIR/lib/amd64" "$PCSC_DIR/lib/arm64"
 93          ar rcs "$PCSC_DIR/lib/amd64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_amd64.o"
 94          ar rcs "$PCSC_DIR/lib/arm64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_arm64.o"
 95
 96          # Create pkg-config file
 97          cat > "$PCSC_DIR/lib/pkgconfig/libpcsclite.pc" << EOF
 98          Name: libpcsclite
 99          Description: PC/SC Lite
100          Version: 1.9.0
101          Cflags: -I$PCSC_DIR/include
102          Libs: -L$PCSC_DIR/lib/amd64 -lpcsclite
103          EOF
104
105          echo "PKG_CONFIG_PATH=$PCSC_DIR/lib/pkgconfig" >> $GITHUB_ENV
106          echo "PCSC_DIR=$PCSC_DIR" >> $GITHUB_ENV
107
108      - name: Get macOS SDK path
109        id: macos_sdk
110        run: echo "path=$(xcrun --show-sdk-path)" >> $GITHUB_OUTPUT
111
112      - name: Run GoReleaser
113        if: steps.tag_version.outputs.new_tag
114        uses: goreleaser/goreleaser-action@v7
115        with:
116          version: latest
117          args: release --clean
118        env:
119          SDK_PATH: ${{ steps.macos_sdk.outputs.path }}
120          GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
121          HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
122
123  snapcraft:
124    runs-on: ${{ matrix.runner }}
125    needs: goreleaser
126    strategy:
127      matrix:
128        include:
129          - arch: amd64
130            runner: ubuntu-latest
131          - arch: arm64
132            runner: ubuntu-24.04-arm
133    steps:
134      - name: Checkout
135        uses: actions/checkout@v6
136        with:
137          fetch-depth: 0
138
139      - name: Install Snapcraft and LXD
140        run: |
141          sudo snap install snapcraft --classic
142          sudo snap install lxd
143          sudo lxd init --auto
144          sudo iptables -P FORWARD ACCEPT
145          sudo usermod -aG lxd $USER
146
147      - name: Build snap
148        run: sg lxd -c 'snapcraft pack --use-lxd --build-for=${{ matrix.arch }}'
149
150      - name: Upload snap
151        env:
152          SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
153        run: snapcraft upload --release=stable *.snap