From 3123209e284f78232f4a013029a9b33e676b3662 Mon Sep 17 00:00:00 2001 From: Mateusz Matoszko Date: Sat, 5 Sep 2026 18:10:17 +0200 Subject: [PATCH] Adds a script for checking urls --- scripts/test_urls.rb | 92 ++++++++++++++++++++++++++++++++++++++++++++ scripts/urls.txt | 27 +++++++++++++ 2 files changed, 119 insertions(+) create mode 100755 scripts/test_urls.rb create mode 100644 scripts/urls.txt diff --git a/scripts/test_urls.rb b/scripts/test_urls.rb new file mode 100755 index 0000000..5748dc0 --- /dev/null +++ b/scripts/test_urls.rb @@ -0,0 +1,92 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Compare blog post URLs from urls.txt against a site. +# +# By default a local `jekyll serve` instance is checked. Pass --live to check +# the same paths against the published site, or --base to point anywhere else. +# +# ./test_urls.rb # http://localhost:4000 +# ./test_urls.rb --live # http://nshint.io +# ./test_urls.rb --base http://staging # anything else + +require 'net/http' +require 'optparse' +require 'uri' + +LIVE_URL = 'http://nshint.io' +LOCAL_URL = 'http://localhost:4000' +URLS_FILE = 'scripts/urls.txt' +USER_AGENT = 'Mozilla/5.0' +TIMEOUT = 10 +MAX_REDIRECTS = 10 + +# HTTP status of `url` after following redirects, or 0 if it could not be +# reached at all. +def status_code(url) + MAX_REDIRECTS.times do + response = get(url) + return response.code.to_i unless response.is_a?(Net::HTTPRedirection) + + url = URI.join(url, response['location']).to_s + end + 0 +rescue StandardError + 0 +end + +def get(url) + uri = URI(url) + Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', + open_timeout: TIMEOUT, read_timeout: TIMEOUT) do |http| + http.request(Net::HTTP::Get.new(uri, 'User-Agent' => USER_AGENT)) + end +end + +def parse_base + base = LOCAL_URL + flags = [] + OptionParser.new do |parser| + parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [--live | --base URL]" + parser.on('--live', "check #{LIVE_URL} instead of the local server") do + flags << '--live' + base = LIVE_URL + end + parser.on('--base URL', 'check this base URL instead of the local server') do |url| + flags << '--base' + base = url + end + end.parse! + abort 'error: --live and --base are mutually exclusive' if flags.size > 1 + + base +end + +def main + base = parse_base + urls = File.readlines(URLS_FILE, chomp: true) + .reject(&:empty?) + .map { |line| URI.join(base, URI(line).path).to_s } + + puts "Testing #{urls.size} URLs from #{URLS_FILE} against #{base}\n\n" + puts format('%-8s %-6s %s', 'Status', 'Code', 'URL') + puts '-' * 80 + + failed = [] + urls.each do |url| + code = status_code(url) + ok = (200...300).cover?(code) + failed << [url, code] unless ok + puts format('%-8s %-6s %s', ok ? 'OK' : 'FAIL', code, url) + end + + puts '-' * 80 + puts "\nResults: #{urls.size - failed.size} OK, #{failed.size} failed" + + return if failed.empty? + + puts "\nFailed URLs:" + failed.each { |url, code| puts " - #{url} (HTTP #{code})" } +end + +main if $PROGRAM_NAME == __FILE__ diff --git a/scripts/urls.txt b/scripts/urls.txt new file mode 100644 index 0000000..fb95b9a --- /dev/null +++ b/scripts/urls.txt @@ -0,0 +1,27 @@ +http://nshint.io/blog/2015/06/23/toggle-slow-animations/ +http://nshint.io/blog/2015/06/24/detailed-exceptions/ +http://nshint.io/blog/2015/06/25/storyboard-localization/ +http://nshint.io/blog/2015/06/27/tracking-drawing-errors/ +http://nshint.io/blog/2015/07/02/fixing-uicatalog-invalid-asset-error/ +http://nshint.io/blog/2015/07/04/how-to-animate-uilabel-properties/ +http://nshint.io/blog/2015/07/05/working-with-coretelephony-framework/ +http://nshint.io/blog/2015/07/12/shared-breakpoints/ +http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/ +http://nshint.io/blog/2015/07/23/run-script-phase-reporting/ +http://nshint.io/blog/2015/08/03/law-of-demeter/ +http://nshint.io/blog/2015/08/04/using-sql-as-date-formatter/ +http://nshint.io/blog/2015/08/09/nsprogressreporting/ +http://nshint.io/blog/2015/08/17/autolayout-breakpoints/ +http://nshint.io/blog/2015/08/24/dont-forget-about-uimotioneffects/ +http://nshint.io/blog/2015/09/02/autolayout-and-nslocalizedstring/ +http://nshint.io/blog/2015/09/14/logging-excessive-blocks-on-the-main-thread/ +http://nshint.io/blog/2015/09/23/uitraitcollection-trick/ +http://nshint.io/blog/2015/10/07/easy-cast-with-_ObjectiveCBridgeable/ +http://nshint.io/blog/2015/10/08/bluetooth-low-energy-the-fun-way/ +http://nshint.io/blog/2015/10/10/working-with-cfunction-pointers-in-swift/ +http://nshint.io/blog/2015/10/23/noescape-attribute/ +http://nshint.io/blog/2016/05/02/wrapping-apis-using-the-builder-pattern/ +http://nshint.io/blog/2019/04/08/testing-the-camera-on-the-simulator/ +http://nshint.io/blog/2019/05/10/testing-codable/ +http://nshint.io/blog/2019/07/13/complete-flows-partial-models/ +http://nshint.io/blog/2020/07/07/array-backwards-compatibility/