-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
dist | ||
Dockerfile | ||
node_modules | ||
packager |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
name: Package and Release | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
after-version: | ||
required: false | ||
type: string | ||
module-base: | ||
required: true | ||
type: string | ||
module-dir: | ||
required: true | ||
type: string | ||
storage-bucket: | ||
required: true | ||
type: string | ||
version-tag: | ||
required: true | ||
type: string | ||
secrets: | ||
r2-access-key-id: | ||
description: "Cloudflare R2 access key ID passed from caller workflow" | ||
required: true | ||
r2-endpoint-url: | ||
description: "Cloudflare R2 jurisdiction-specific endpoint URL" | ||
required: true | ||
r2-secret-access-key: | ||
description: "A secret access key passed from the caller workflow" | ||
required: true | ||
|
||
jobs: | ||
package: | ||
name: Package | ||
runs-on: ubuntu-latest | ||
env: | ||
AWS_DEFAULT_REGION: auto | ||
AWS_ACCESS_KEY_ID: ${{ secrets.r2-access-key-id }} | ||
AWS_ENDPOINT_URL: ${{ secrets.r2-endpoint-url }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.r2-secret-access-key }} | ||
OUTPUT_DIR: /tmp/mod-zip-result | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 1 | ||
|
||
- name: Install Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
cache: "npm" | ||
cache-dependency-path: package-lock.json | ||
node-version: "20.12.2" | ||
|
||
- name: Install dependencies | ||
run: npm install | ||
shell: sh | ||
|
||
- name: Build JS 🏗️ | ||
run: npm exec vite build | ||
|
||
- name: Setup Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
check-latest: true | ||
go-version-file: "packager/go.mod" | ||
cache-dependency-path: | | ||
packager/go.sum | ||
- name: Display Go version | ||
run: go version | ||
|
||
- name: Install dependencies | ||
working-directory: ./packager | ||
run: | | ||
echo "::group::go get" | ||
go get -t ./... | ||
echo "::endgroup::" | ||
- name: Build packager | ||
working-directory: ./packager | ||
run: go install . | ||
|
||
- name: Fetch tags | ||
run: git fetch --tags -f origin | ||
|
||
- name: Determine module names and version details | ||
id: module_info | ||
run: | | ||
BASE_MODULE_NAME=${{ inputs.module-base }} | ||
MODULE_NAME=$(go list -m) | ||
echo "base_module_name=${BASE_MODULE_NAME}" >> $GITHUB_OUTPUT | ||
echo "module_name=${MODULE_NAME}" >> $GITHUB_OUTPUT | ||
if [ "$MODULE_NAME" == "$BASE_MODULE_NAME" ]; then | ||
TAG_PREFIX="" | ||
else | ||
TAG_PREFIX=${MODULE_NAME#$BASE_MODULE_NAME/}/ | ||
fi | ||
echo "tag_prefix=${TAG_PREFIX}" >> $GITHUB_OUTPUT | ||
VERSION_TAG=${{ inputs.version-tag }} | ||
echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT | ||
VERSION_NUMBER=${VERSION_TAG#$TAG_PREFIX} | ||
echo "version_number=${VERSION_NUMBER}" >> $GITHUB_OUTPUT | ||
working-directory: ${{ inputs.module-dir }} | ||
|
||
- name: Extract timestamp | ||
id: extract_timestamp | ||
run: echo "timestamp=$(git log -1 --format=%ct ${{ steps.module_info.outputs.version_tag }})" >> $GITHUB_OUTPUT | ||
|
||
- name: print stuff | ||
run: | | ||
echo "base module: ${{ steps.module_info.outputs.base_module_name }}" | ||
echo "module: ${{ steps.module_info.outputs.module_name }}" | ||
echo "tag_prefix: ${{ steps.module_info.outputs.tag_prefix }}" | ||
echo "timestamp: ${{ steps.extract_timestamp.outputs.timestamp }}" | ||
echo "version_tag: ${{ steps.module_info.outputs.version_tag }}" | ||
echo "version_number: ${{ steps.module_info.outputs.version_number }}" | ||
- name: Remove all undesirable files | ||
# Remove all files that we don't want to end up in the final mod release .zip file, including: | ||
# * node_modules | ||
# * UI source files, .json, .js | ||
run: | | ||
rm -r .eslintrc.cjs .github .storybook .stylelintignore .vscode node_modules package.json package-lock.json public src | ||
find . -type f -name '*.json' -exec rm -f {} + | ||
- name: Package module | ||
# if: startsWith(github.ref, 'refs/tags/') | ||
run: | | ||
packager \ | ||
-dir ${{ inputs.module-dir }} \ | ||
-output ${{ env.OUTPUT_DIR }} \ | ||
-mod ${{ steps.module_info.outputs.module_name }} \ | ||
-timestamp ${{ steps.extract_timestamp.outputs.timestamp }} \ | ||
-version ${{ steps.module_info.outputs.version_number }} | ||
- name: Extract sorted version list and write files | ||
id: version_list | ||
run: | | ||
AFTER_VERSION="${{ inputs.after-version }}" | ||
TAG_PREFIX="${{ steps.module_info.outputs.tag_prefix }}" | ||
TAG_MATCHER="${TAG_PREFIX}v*" | ||
if [ -n "$AFTER_VERSION" ]; then | ||
VERSION_LIST=$(git tag -l "$TAG_MATCHER" | sed "s#^$TAG_PREFIX##" | sort -V | awk -v threshold="$AFTER_VERSION" '$0 > threshold') | ||
else | ||
VERSION_LIST=$(git tag -l "$TAG_MATCHER" | sed "s#^$TAG_PREFIX##" | sort -V) | ||
fi | ||
LATEST_VERSION=$(echo "$VERSION_LIST" | tail -n 1) | ||
echo "Latest version: $LATEST_VERSION" | ||
echo "All versions:" | ||
echo "$VERSION_LIST" | ||
if [ -z "$VERSION_LIST" ]; then | ||
echo "Error: Version list is empty." | ||
exit 1 | ||
fi | ||
if [ -z "$LATEST_VERSION" ]; then | ||
echo "Error: Latest version is empty." | ||
exit 1 | ||
fi | ||
echo "latest_version=${LATEST_VERSION}" >> $GITHUB_OUTPUT | ||
echo "$VERSION_LIST" > ${{ env.OUTPUT_DIR }}/${{ steps.module_info.outputs.module_name }}/@v/list | ||
- name: List results | ||
run: | | ||
tree ${{ env.OUTPUT_DIR }} | ||
ls -la ${{ env.OUTPUT_DIR }}/${{ steps.module_info.outputs.module_name }} | ||
ls -la ${{ env.OUTPUT_DIR }}/${{ steps.module_info.outputs.module_name }}/@v | ||
cat ${{ env.OUTPUT_DIR }}/${{ steps.module_info.outputs.module_name }}/@v/list | ||
- name: Sync files to R2 | ||
run: | | ||
aws s3 cp ${{ env.OUTPUT_DIR }}/${{ steps.module_info.outputs.module_name }}/@v/ s3://${{ inputs.storage-bucket }}/${{ steps.module_info.outputs.module_name }}/@v/ --recursive | ||
aws s3 cp s3://${{ inputs.storage-bucket }}/${{ steps.module_info.outputs.module_name }}/@v/${{ steps.version_list.outputs.latest_version }}.info s3://${{ inputs.storage-bucket }}/${{ steps.module_info.outputs.module_name }}/@latest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: Release | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
- "*" | ||
tags: | ||
# Additional packages must be added both here AND in the job list below: | ||
- "v*" | ||
|
||
jobs: | ||
release_riverui: | ||
uses: ./.github/workflows/package-and-release.yaml | ||
if: startsWith(github.ref, 'refs/tags/v') | ||
with: | ||
after-version: v0.4.0 | ||
module-base: riverqueue.com/riverui | ||
module-dir: . | ||
storage-bucket: ${{ vars.RELEASE_STORAGE_BUCKET }} | ||
version-tag: ${{ github.ref_name}} | ||
permissions: | ||
contents: read | ||
secrets: | ||
r2-access-key-id: ${{ secrets.R2_ACCESS_KEY_ID }} | ||
r2-endpoint-url: ${{ secrets.R2_ENDPOINT_URL }} | ||
r2-secret-access-key: ${{ secrets.R2_SECRET_ACCESS_KEY }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
.env | ||
.env.* | ||
!.env.example | ||
/packager/packager | ||
.tool-versions | ||
/riverui | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module riverqueue.com/riverqueue/packager | ||
|
||
go 1.23 | ||
|
||
toolchain go1.23.0 | ||
|
||
require golang.org/x/mod v0.18.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= | ||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= | ||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= | ||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"flag" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"time" | ||
|
||
"golang.org/x/mod/module" | ||
"golang.org/x/mod/semver" | ||
"golang.org/x/mod/zip" | ||
) | ||
|
||
func main() { | ||
if err := createBundle(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func createBundle() error { | ||
var ( | ||
dir string | ||
mod string | ||
outputDirPath string | ||
timestampInt int64 | ||
versionString string | ||
) | ||
flag.StringVar(&dir, "dir", "", "dir to package up") | ||
flag.StringVar(&mod, "mod", "", "module name, i.e. github.com/user/repo") | ||
flag.Int64Var(×tampInt, "timestamp", 0, "timestamp of the version") | ||
flag.StringVar(&outputDirPath, "output", "", "output directory path, which will include a fully nested directory structure for the module name") | ||
flag.StringVar(&versionString, "version", "", "version of the module") | ||
|
||
flag.Parse() | ||
|
||
if dir == "" { | ||
return errors.New("dir is required") | ||
} | ||
if outputDirPath == "" { | ||
return errors.New("output is required") | ||
} | ||
if mod == "" { | ||
return errors.New("mod is required") | ||
} | ||
if timestampInt == 0 { | ||
return errors.New("timestamp is required") | ||
} | ||
if versionString == "" { | ||
return errors.New("version is required") | ||
} | ||
|
||
if !semver.IsValid(versionString) { | ||
return errors.New("version is not valid") | ||
} | ||
|
||
// Convert the timestamp to a time.Time object: | ||
timestamp := time.Unix(timestampInt, 0).UTC() | ||
|
||
nestedOutputDir := filepath.Join(outputDirPath, mod) | ||
vOutputDir := filepath.Join(nestedOutputDir, "@v") | ||
|
||
if err := os.MkdirAll(vOutputDir, 0o700); err != nil { | ||
return err | ||
} | ||
|
||
version := module.Version{ | ||
Path: mod, | ||
Version: versionString, | ||
} | ||
|
||
modFilename := version.Version + ".mod" | ||
zipFilename := version.Version + ".zip" | ||
|
||
modFileContents, err := os.ReadFile(filepath.Join(dir, "go.mod")) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := os.WriteFile(filepath.Join(vOutputDir, modFilename), modFileContents, 0o644); err != nil { | ||
return err | ||
} | ||
|
||
f, err := os.OpenFile(filepath.Join(vOutputDir, zipFilename), os.O_CREATE|os.O_WRONLY, 0o644) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
if err := zip.CreateFromDir(f, version, dir); err != nil { | ||
return err | ||
} | ||
|
||
info := Info{ | ||
Version: version.Version, | ||
Time: timestamp, | ||
} | ||
|
||
infoFile, err := os.Create(filepath.Join(vOutputDir, version.Version+".info")) | ||
if err != nil { | ||
return err | ||
} | ||
defer infoFile.Close() | ||
|
||
if err := json.NewEncoder(infoFile).Encode(info); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type Info struct { | ||
Version string // version string | ||
Time time.Time // commit time | ||
} |