-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create Makefile & release pipeline, make git-bundle-server web-server
more resilient
#12
Conversation
(I co-assigned myself to remind me to review this, but I won't have time until next week.) |
um, WOW!!! Let me just stop there. I want to steal so much of this for my thing... :-) I promise I'll give it a more "critical" review shortly. |
echo "$*" >&2 | ||
exit 1 | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find that "set -x" is helpful when there is a lot happening that could go wrong....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up not adding set -x
(although it did inspire me to add set -e
, which helped avoid all the || exit 1
s), since it's probably more verbose than typical execution needs. That said, I think it'll be valuable to have that option, so I opened an issue to add it in the future: #14
It installed successfully on my M1 mac. The |
However, when running the uninstall script, I got an error. (I'm not sure that the web-server was running.)
And the files are still in /usr/local/ |
Welp, that's what I get for not testing the uninstall script properly - I tested running it after starting the web server, so the plist was populated. I need to add a check that the file exists - if it doesn't, The more annoying thing is that you get a different, more informative error code when running |
Remove "Whether to" from description of the '--force' option for 'git-bundle-server web-server start'. To a user, the '--force' option is not a boolean, so the description should describe what '--force' does when specified. Signed-off-by: Victoria Dye <[email protected]>
9ac003e
to
386c0c7
Compare
@jeffhostetler I've made some changes to |
This one installed and uninstalled just fine. (I never started the web-server, so this was a minimal test at best.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff! I learned some new things, especially in the Makefile realm.
@@ -0,0 +1,22 @@ | |||
# Default target |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This Makefile is really simple and lovely.
"[makefile]": { | ||
"editor.detectIndentation": false, | ||
"editor.insertSpaces": false, | ||
"editor.tabSize": 8, | ||
"editor.wordWrap": "off", | ||
"files.trimTrailingWhitespace": true, | ||
}, | ||
"[shellscript]": { | ||
"editor.detectIndentation": false, | ||
"editor.insertSpaces": false, | ||
"editor.tabSize": 8, | ||
"editor.wordWrap": "off", | ||
"files.trimTrailingWhitespace": true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good guardrails
draft: true, | ||
tag_name: tagName, | ||
name: tagName, | ||
generate_release_notes: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spiffy!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking forward to using the generated release notes in a new project. Having all of the releases match this generated format should help, as opposed to other places where an established release note pattern doesn't match the generated notes.
8aecd69
to
5592056
Compare
git-bundle-server web-server
more resilient
5592056
to
b8052aa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I enjoyed reading this. I'm glad you were able to synthesize and improve upon our existing release workflows. Did you notice anything you would like to improve in the originals?
if !fileExists || force { | ||
// TODO: only overwrite file if file contents have changed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticing this TODO
and agreeing that this should be handled later.
# Platform information | ||
GOOS := $(shell go env GOOS) | ||
GOARCH := $(shell go env GOARCH) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are set from go env
here, but you mention they could be modified later. I'll keep an eye out for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revisiting this: I was incorrect. You are not manually overriding these, but using them to decide which kind of installer is necessary. I was expecting this to need to change to build macOS ARM binaries on intel machines, but I don't see that changing in those workflows.
$(PKGDIR)/payload: check-arch build | ||
@echo | ||
@echo "======== Formatting package contents ========" | ||
@build/package/layout-unix.sh --bindir="$(BINDIR)" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticing that you're able to share a lot in this script between Linux and macOS. layout-unix
is a good name for that.
draft: true, | ||
tag_name: tagName, | ||
name: tagName, | ||
generate_release_notes: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking forward to using the generated release notes in a new project. Having all of the releases match this generated format should help, as opposed to other places where an established release note pattern doesn't match the generated notes.
829e901
to
984dcb8
Compare
984dcb8
to
2f3722a
Compare
If a service unit configuration file doesn't exist on disk, 'systemctl stop' fails with error code 5 [1]. To keep 'git-bundle-server web-server stop' from failing when 'web-server start' was not called before it, do not cause the program to fail when the error code indicates the service isn't installed. Add a test covering this case. [1] https://freedesktop.org/software/systemd/man/systemd.exec.html#Process%20Exit%20Codes Signed-off-by: Victoria Dye <[email protected]>
Change the launch agent domain from 'gui/<uid>' (tied to login session) to 'user/<uid>' (tied to user, but may run when logged out). To allow the agent to be loaded with this new domain, explicitly set the 'LimitLoadToSessionType' value in the generated plist to 'Background' (default value seems to be 'Aqua', corresponding to the logged in session i.e. 'gui/<uid>' domain). Signed-off-by: Victoria Dye <[email protected]>
Change 'bootoutFile()' helper to 'bootout()' to unload a launchd service based on its service target identifier (e.g. 'gui/502/com.example.myservice') rather than the path to its plist file. This use of 'bootout' is both less fragile (since it does not require a plist file to exist to succeed) and easier to use when performing a "gentle" removal (i.e., suppressing "service not found" errors). Update 'Create()' and the 'launchd' tests with the updated bootout behavior. Signed-off-by: Victoria Dye <[email protected]>
Add a '--remove' option to 'git-bundle-server web-server stop' to fully remove the service daemon and its resources on disk after stopping the daemon process. For launchd, this is done by first running 'launchctl bootout' on the appropriate service, then removing the plist file; for systemd, the service unit file is removed then 'systemctl daemon-reload' is run. Neither implementation fails if the web server was never loaded. Although it is unlikely that users will need this option in day-to-day use, this cleanup option will be needed to fully remove bundle server resources in the uninstall scripts implemented in later patches. Signed-off-by: Victoria Dye <[email protected]>
Later patches will create releasable packages of the repository's software with the name 'git-bundle-server'. To keep the web-server daemon process naming consistent, as well as generally provide a bit of specificity to the daemon name, change 'com.github.bundleserver' to 'com.github.gitbundleserver'. Signed-off-by: Victoria Dye <[email protected]>
Popular convention in Go projects seems to be using Makefiles for automating build/release tasks [1]. In anticipation of adding complex packaging scripts in future patches, create an initial Makefile with basic 'build' and 'clean' targets. Note that the 'build' target utilizes the 'GOOS' and 'GOARCH' of the environment to allow generating executables for any supported Go platform, defaulting to the current platform the build is running on. This behavior will be critical in later patches, when we want to create MacOS ARM64 packages on MacOS Intel build machines. [1] https://github.com/golang-standards/project-layout/tree/master#scripts Signed-off-by: Victoria Dye <[email protected]>
2f3722a
to
be5d4d9
Compare
Update: after testing on an Ubuntu VM, I found that 1) some fixes I had made to the Debian Range diff -: ------- > 1: 374758a systemd: do not fail 'stop' if service unit not installed
1: 4e4341c = 2: 02282c4 launchd: enable running after user logs out
2: 008d5de = 3: 8c6a468 launchd: unload by service target rather than filename
3: 7645b2f = 4: c82b8e0 web-server: add '--remove' option to 'stop'
4: d656905 = 5: 7660c16 web-server: rename daemon to align with package naming
5: 3371111 = 6: be8f1ea Makefile: create basic 'build' and 'clean' targets
6: 0fb5df8 ! 7: 18c1ddc Makefile: add Debian packaging targets
@@ Makefile: build:
+ @echo
+ @echo "======== Creating binary Debian package ========"
+ @build/package/deb/pack.sh --payload="$(DEBDIR)/root" \
++ --scripts="$(CURDIR)/build/package/deb/scripts" \
+ --arch="$(PACKAGE_ARCH)" \
+ --version="$(VERSION)" \
+ --output="$(DEB_FILENAME)"
@@ build/package/deb/pack.sh (new)
+ DEBROOT="${i#*=}"
+ shift # past argument=value
+ ;;
++ --scripts=*)
++ SCRIPT_DIR="${i#*=}"
++ shift # past argument=value
++ ;;
+ --arch=*)
+ ARCH="${i#*=}"
+ shift # past argument=value
@@ build/package/deb/pack.sh (new)
+mkdir -p "$(dirname "$DEBOUT")"
+
+# Build .deb
-+mkdir -p "$DEBROOT/DEBIAN"
++mkdir -m 755 -p "$DEBROOT/DEBIAN"
+
+# Create the debian control file
+cat >"$DEBROOT/DEBIAN/control" <<EOF
@@ build/package/deb/pack.sh (new)
+Description: A self-hostable Git bundle server.
+EOF
+
++# Copy the maintainer scripts, if they exist
++if [ -d "$SCRIPT_DIR" ]; then
++ cp -R "$SCRIPT_DIR/." "$DEBROOT/DEBIAN"
++fi
++
+dpkg-deb -Zxz --build "$DEBROOT" "$DEBOUT"
## build/package/deb/scripts/prerm (new) ##
@@ build/package/deb/scripts/prerm (new)
+#!/bin/bash
+set -e
+
-+# Stop & cleanup the web server
-+/usr/local/git-bundle-server/bin/git-bundle-server web-server stop --remove
++# Stop & cleanup the web server as the logged-in user
++# The XDG_RUNTIME_DIR is required for 'systemctl' to work, so we manually set it
++# to that of the logged-in user.
++LOGGED_IN_USER="${SUDO_USER:-${USER}}"
++LOGGED_IN_UID="$(sudo -u $LOGGED_IN_USER id -u)"
++sudo -u $LOGGED_IN_USER XDG_RUNTIME_DIR=/run/user/$LOGGED_IN_UID \
++ /usr/local/git-bundle-server/bin/git-bundle-server web-server stop --remove
+
+exit 0
@@ build/package/layout-unix.sh (new)
+fi
+
+# Ensure payload directory exists
-+INSTALL_TO="$PAYLOAD/usr/local/git-bundle-server/"
++INSTALL_TO="$PAYLOAD/usr/local/git-bundle-server"
+mkdir -p "$INSTALL_TO"
+
+# Copy built binaries
@@ build/package/layout-unix.sh (new)
+
+# Create symlinks
+if [ -n "$INCLUDE_SYMLINKS" ]; then
-+ LINK_TO="$DEBROOT/usr/local/bin/"
++ LINK_TO="$PAYLOAD/usr/local/bin"
+ mkdir -p "$LINK_TO"
+
+ echo "Creating symlinks..."
7: dfdc338 ! 8: 54f27ff Makefile: add MacOS packaging targets
@@ build/package/layout-unix.sh: mkdir -p "$INSTALL_TO"
+
# Create symlinks
if [ -n "$INCLUDE_SYMLINKS" ]; then
- LINK_TO="$DEBROOT/usr/local/bin/"
+ LINK_TO="$PAYLOAD/usr/local/bin"
## build/package/pkg/entitlements.xml (new) ##
@@
8: 91fe6c6 = 9: 5e797e8 release.yml: create release pipeline
9: e971c13 = 10: d9ef2bd release.yml: create draft release with artifacts The good news is that I've confirmed the user-scoped service in EDIT: and here's a new release build |
I tested this on my Intel Mac and installation succeeded without issue. I ran into #13, so I added my error message to that description. After fixing the missing directory issue, I did get this prompt: I suppose this is inevitable for the macOS ecosystem, but something to be aware of, right? |
Add 'package' target to Makefile that, based on the 'GOOS', builds the platform-appropriate package. For now, support only binary .deb packages (corresponding to a 'GOOS' of 'linux'); if the 'GOOS' is unsupported, 'make' will exit with an error. The .deb packaging process is broken into three steps, each corresponding to a target in the Makefile: 1. Build the executables. 2. Copy the executables & any symlinks into the appropriate file structure for running 'dpkg-deb'. 3. Generate the control file, copy the maintainer script(s) [1], and build the package with 'dpkg-deb'. Additionally, the 'check-arch' and 'check-version' targets verify that the 'GOARCH' is supported for packaging on the platform and that a version string is set, respectively. In accordance with the 'project-layout' guidelines for the Makefile [2], most of the packaging logic outlined above lives in dedicated scripts. Best practice for the location of these scripts is somewhat vague, since it appears that both 'scripts/' [3] and 'build/package/' [4] would be valid choices. Go with the latter, putting the scripts in 'build/package' (if they will apply to more than one packaging mechanism) or a 'deb' subdirectory for Debian-specific configuration. [1] https://www.debian.org/doc/debian-policy/ap-flowcharts.html [2] https://github.com/golang-standards/project-layout/tree/master#scripts [3] https://github.com/golang-standards/project-layout/blob/master/scripts/README.md [4] https://github.com/golang-standards/project-layout/blob/master/build/README.md Signed-off-by: Victoria Dye <[email protected]>
Add support for creating MacOS .pkg packages in the Makefile. Similar to the Debian packaging routine, this is broken into four steps: 1. Build the executables. 2. Copy executables & 'uninstall.sh' into the appropriate file structure to build the .pkg file. 3. Build the component package with 'pkgbuild' and the full package with 'productbuild'. Signed-off-by: Victoria Dye <[email protected]>
Create a basic release pipeline that triggers when a tag of the correct format ("v<number>.<number>.<number>...") is pushed. The pipeline generates three artifacts: 1. An x86/64 .deb binary package 2. An x86/64 MacOS .pkg 3. An ARM64 MacOS .pkg At the moment, these packages are simply uploaded as artifacts in the workflow. In the future, the goal is to automatically create and attach these artifacts to a draft release, to allow maintainers to add release note details then publish with the necessary attachments. Note that the tag filtering in GitHub Actions isn't fancy enough to allow for full verification of the version, so a tag like "v1a.2b.3c-xyz" would trigger the pipeline. Better protections will be put in place later, but for now we can rely on maintainers to push only valid tags for the pipeline. Signed-off-by: Victoria Dye <[email protected]>
Add a job, dependent on the success of all packaging steps, to download the generated artifacts and attach them to a newly-created draft release. The created draft release description is populated with auto-generated release notes [1]. Note the intermediate step "Consolidate artifact directory"; because downloading all artifacts with the 'download-artifacts' action creates a wrapper directory around each artifact [2], we remove those wrappers by moving all files into a single consolidated 'artifacts' directory before running the release creation & attachment script. [1] https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes [2] https://github.com/actions/download-artifact#download-all-artifacts Signed-off-by: Victoria Dye <[email protected]>
be5d4d9
to
3259e5f
Compare
That's interesting, I haven't seen that notification (whether I install from a package built locally or from the one generated by the release pipeline). The only one I've encountered is this one when starting the web server: My guess would be that it's something |
I've had to add git-telemetry-service manually to my firewall settings. It's well hidden under the "options..." page on the "firewall" page. However, it looks like there might be a way to add an exception/open a port from the command line. |
Hey, just found this while working on a preview package (and stealing generously from this PR). There's an With source looking like this:
We can force a new value at compile time using:
I'm still experimenting, but it looks promising. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the details and significant work here. It's a great foundation to expand upon more later.
Summary
This series is made up of a few loosely-connected changes:
git-bundle-server web-server
, mainly making the services more resilient to configuration issues & allowing more flexible running (e.g., starting the service and having it continue after a user logs off).Makefile
and packaging logic for MacOS .pkg files and binary Debian .deb files.Prior Art
microsoft/git
-build-git-installers.yml
This release pipeline is the source of both the variable calculation in the
prereqs
step and thecreate-github-release
step. Note that the latter is updated to handlePromise
s a bit more carefully, uses a new version ofgithub-script
(and therefore changes references ofgithub
togithub.rest
1), and includes an intermediate step to move artifacts into a single directory before upload.GitCredentialManager/git-credential-manager
- misc. scripts (1, 2, 3)The scripts found in
build/package
here are derived from those linked in GCM. There were a lot of minor tweaks to adjust to this codebase, but some major differences include:die "unknown option '$i'"
catch to fail if unidentified options are passed to the scripts (rather than just ignoring them)pkgbuild
andproductbuild
steps into a single script (pkg/pack.sh
)productbuild
, namely leaving out thedistribution.xml
& localization resourcesgit-bundle-server web-server stop --remove
to the uninstall scripts, run as the logged-in user (not root, despite the uninstall script otherwise executing as root)prerm
script for the Debian package (to stop and clean up the web server, if needed)Testing
Successful pipeline run
Draft release (screenshot)
Other
I've locally built, installed, and uninstalled the packages on both my (Intel) Mac and an Ubuntu Codespace.
If you get the chance, I'd love it if y'all could try installing the generated artifacts (found here), especially if you use an M1 Mac. To see if the install worked, run
git-bundle-server -h
and you should get help text.Future work
git-bundle-server init
while testing a local setup. It seems pretty minor, but not particularly related to this PR, so I'll leave it out for now.Footnotes
https://github.com/actions/github-script#breaking-changes-in-v5 ↩